mirror of https://github.com/pikami/cosmium.git
Added support for query parameters
This commit is contained in:
parent
f183f308fb
commit
03623e5a82
|
@ -109,8 +109,13 @@ func DocumentsPost(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var queryParameters map[string]interface{}
|
||||||
|
if paramsArray, ok := requestBody["parameters"].([]interface{}); ok {
|
||||||
|
queryParameters = parametersToMap(paramsArray)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Handle these {"query":"select c.id, c._self, c._rid, c._ts, [c[\"pk\"]] as _partitionKeyValue from c"}
|
// TODO: Handle these {"query":"select c.id, c._self, c._rid, c._ts, [c[\"pk\"]] as _partitionKeyValue from c"}
|
||||||
docs, status := repositories.ExecuteQueryDocuments(databaseId, collectionId, query.(string))
|
docs, status := repositories.ExecuteQueryDocuments(databaseId, collectionId, query.(string), queryParameters)
|
||||||
if status != repositorymodels.StatusOk {
|
if status != repositorymodels.StatusOk {
|
||||||
// TODO: Currently we return everything if the query fails
|
// TODO: Currently we return everything if the query fails
|
||||||
GetAllDocuments(c)
|
GetAllDocuments(c)
|
||||||
|
@ -139,3 +144,15 @@ func DocumentsPost(c *gin.Context) {
|
||||||
|
|
||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Unknown error"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parametersToMap(pairs []interface{}) map[string]interface{} {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
|
||||||
|
for _, pair := range pairs {
|
||||||
|
if pairMap, ok := pair.(map[string]interface{}); ok {
|
||||||
|
result[pairMap["name"].(string)] = pairMap["value"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -13,11 +13,18 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, query string, expectedData []interface{}) {
|
func testCosmosQuery(t *testing.T,
|
||||||
|
collectionClient *azcosmos.ContainerClient,
|
||||||
|
query string,
|
||||||
|
queryParameters []azcosmos.QueryParameter,
|
||||||
|
expectedData []interface{},
|
||||||
|
) {
|
||||||
pager := collectionClient.NewQueryItemsPager(
|
pager := collectionClient.NewQueryItemsPager(
|
||||||
query,
|
query,
|
||||||
azcosmos.PartitionKey{},
|
azcosmos.PartitionKey{},
|
||||||
&azcosmos.QueryOptions{})
|
&azcosmos.QueryOptions{
|
||||||
|
QueryParameters: queryParameters,
|
||||||
|
})
|
||||||
|
|
||||||
context := context.TODO()
|
context := context.TODO()
|
||||||
items := make([]interface{}, 0)
|
items := make([]interface{}, 0)
|
||||||
|
@ -70,6 +77,7 @@ func Test_Documents(t *testing.T) {
|
||||||
t.Run("Should query document", func(t *testing.T) {
|
t.Run("Should query document", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT c.id, c[\"pk\"] FROM c",
|
"SELECT c.id, c[\"pk\"] FROM c",
|
||||||
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "12345", "pk": "123"},
|
map[string]interface{}{"id": "12345", "pk": "123"},
|
||||||
map[string]interface{}{"id": "67890", "pk": "456"},
|
map[string]interface{}{"id": "67890", "pk": "456"},
|
||||||
|
@ -80,6 +88,7 @@ func Test_Documents(t *testing.T) {
|
||||||
t.Run("Should query VALUE array", func(t *testing.T) {
|
t.Run("Should query VALUE array", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT VALUE [c.id, c[\"pk\"]] FROM c",
|
"SELECT VALUE [c.id, c[\"pk\"]] FROM c",
|
||||||
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
[]interface{}{"12345", "123"},
|
[]interface{}{"12345", "123"},
|
||||||
[]interface{}{"67890", "456"},
|
[]interface{}{"67890", "456"},
|
||||||
|
@ -90,6 +99,7 @@ func Test_Documents(t *testing.T) {
|
||||||
t.Run("Should query VALUE object", func(t *testing.T) {
|
t.Run("Should query VALUE object", func(t *testing.T) {
|
||||||
testCosmosQuery(t, collectionClient,
|
testCosmosQuery(t, collectionClient,
|
||||||
"SELECT VALUE { id: c.id, _pk: c.pk } FROM c",
|
"SELECT VALUE { id: c.id, _pk: c.pk } FROM c",
|
||||||
|
nil,
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "12345", "_pk": "123"},
|
map[string]interface{}{"id": "12345", "_pk": "123"},
|
||||||
map[string]interface{}{"id": "67890", "_pk": "456"},
|
map[string]interface{}{"id": "67890", "_pk": "456"},
|
||||||
|
@ -102,6 +112,21 @@ func Test_Documents(t *testing.T) {
|
||||||
`select c.id
|
`select c.id
|
||||||
FROM c
|
FROM c
|
||||||
WHERE c.isCool=true`,
|
WHERE c.isCool=true`,
|
||||||
|
nil,
|
||||||
|
[]interface{}{
|
||||||
|
map[string]interface{}{"id": "67890"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should query document with query parameters", func(t *testing.T) {
|
||||||
|
testCosmosQuery(t, collectionClient,
|
||||||
|
`select c.id
|
||||||
|
FROM c
|
||||||
|
WHERE c.id=@param_id`,
|
||||||
|
[]azcosmos.QueryParameter{
|
||||||
|
{Name: "@param_id", Value: "67890"},
|
||||||
|
},
|
||||||
[]interface{}{
|
[]interface{}{
|
||||||
map[string]interface{}{"id": "67890"},
|
map[string]interface{}{"id": "67890"},
|
||||||
},
|
},
|
||||||
|
|
|
@ -103,7 +103,7 @@ func CreateDocument(databaseId string, collectionId string, document map[string]
|
||||||
return repositorymodels.StatusOk
|
return repositorymodels.StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteQueryDocuments(databaseId string, collectionId string, query string) ([]memoryexecutor.RowType, repositorymodels.RepositoryStatus) {
|
func ExecuteQueryDocuments(databaseId string, collectionId string, query string, queryParameters map[string]interface{}) ([]memoryexecutor.RowType, repositorymodels.RepositoryStatus) {
|
||||||
parsedQuery, err := nosql.Parse("", []byte(query))
|
parsedQuery, err := nosql.Parse("", []byte(query))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to parse query: %s\nerr: %v", query, err)
|
log.Printf("Failed to parse query: %s\nerr: %v", query, err)
|
||||||
|
@ -120,5 +120,10 @@ func ExecuteQueryDocuments(databaseId string, collectionId string, query string)
|
||||||
covDocs = append(covDocs, map[string]interface{}(doc))
|
covDocs = append(covDocs, map[string]interface{}(doc))
|
||||||
}
|
}
|
||||||
|
|
||||||
return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), repositorymodels.StatusOk
|
if typedQuery, ok := parsedQuery.(parsers.SelectStmt); ok {
|
||||||
|
typedQuery.Parameters = queryParameters
|
||||||
|
return memoryexecutor.Execute(typedQuery, covDocs), repositorymodels.StatusOk
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, repositorymodels.BadRequest
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ const (
|
||||||
ConstantTypeInteger
|
ConstantTypeInteger
|
||||||
ConstantTypeFloat
|
ConstantTypeFloat
|
||||||
ConstantTypeBoolean
|
ConstantTypeBoolean
|
||||||
|
ConstantTypeParameterConstant
|
||||||
)
|
)
|
||||||
|
|
||||||
type SelectItemType int
|
type SelectItemType int
|
||||||
|
@ -29,6 +30,7 @@ type SelectStmt struct {
|
||||||
Table Table
|
Table Table
|
||||||
Filters interface{}
|
Filters interface{}
|
||||||
Count int
|
Count int
|
||||||
|
Parameters map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Table struct {
|
type Table struct {
|
||||||
|
|
|
@ -1197,20 +1197,47 @@ var g = &grammar{
|
||||||
pos: position{line: 208, col: 60, offset: 5787},
|
pos: position{line: 208, col: 60, offset: 5787},
|
||||||
name: "BooleanLiteral",
|
name: "BooleanLiteral",
|
||||||
},
|
},
|
||||||
|
&ruleRefExpr{
|
||||||
|
pos: position{line: 208, col: 77, offset: 5804},
|
||||||
|
name: "ParameterConstant",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ParameterConstant",
|
||||||
|
pos: position{line: 210, col: 1, offset: 5823},
|
||||||
|
expr: &actionExpr{
|
||||||
|
pos: position{line: 210, col: 22, offset: 5844},
|
||||||
|
run: (*parser).callonParameterConstant1,
|
||||||
|
expr: &seqExpr{
|
||||||
|
pos: position{line: 210, col: 22, offset: 5844},
|
||||||
|
exprs: []any{
|
||||||
|
&litMatcher{
|
||||||
|
pos: position{line: 210, col: 22, offset: 5844},
|
||||||
|
val: "@",
|
||||||
|
ignoreCase: false,
|
||||||
|
want: "\"@\"",
|
||||||
|
},
|
||||||
|
&ruleRefExpr{
|
||||||
|
pos: position{line: 210, col: 26, offset: 5848},
|
||||||
|
name: "Identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IntegerLiteral",
|
name: "IntegerLiteral",
|
||||||
pos: position{line: 210, col: 1, offset: 5803},
|
pos: position{line: 214, col: 1, offset: 5965},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 210, col: 19, offset: 5821},
|
pos: position{line: 214, col: 19, offset: 5983},
|
||||||
run: (*parser).callonIntegerLiteral1,
|
run: (*parser).callonIntegerLiteral1,
|
||||||
expr: &labeledExpr{
|
expr: &labeledExpr{
|
||||||
pos: position{line: 210, col: 19, offset: 5821},
|
pos: position{line: 214, col: 19, offset: 5983},
|
||||||
label: "number",
|
label: "number",
|
||||||
expr: &ruleRefExpr{
|
expr: &ruleRefExpr{
|
||||||
pos: position{line: 210, col: 26, offset: 5828},
|
pos: position{line: 214, col: 26, offset: 5990},
|
||||||
name: "Integer",
|
name: "Integer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1218,32 +1245,32 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "StringLiteral",
|
name: "StringLiteral",
|
||||||
pos: position{line: 213, col: 1, offset: 5929},
|
pos: position{line: 217, col: 1, offset: 6091},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 213, col: 18, offset: 5946},
|
pos: position{line: 217, col: 18, offset: 6108},
|
||||||
run: (*parser).callonStringLiteral1,
|
run: (*parser).callonStringLiteral1,
|
||||||
expr: &seqExpr{
|
expr: &seqExpr{
|
||||||
pos: position{line: 213, col: 18, offset: 5946},
|
pos: position{line: 217, col: 18, offset: 6108},
|
||||||
exprs: []any{
|
exprs: []any{
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 213, col: 18, offset: 5946},
|
pos: position{line: 217, col: 18, offset: 6108},
|
||||||
val: "\"",
|
val: "\"",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\"\"",
|
want: "\"\\\"\"",
|
||||||
},
|
},
|
||||||
&labeledExpr{
|
&labeledExpr{
|
||||||
pos: position{line: 213, col: 23, offset: 5951},
|
pos: position{line: 217, col: 23, offset: 6113},
|
||||||
label: "chars",
|
label: "chars",
|
||||||
expr: &zeroOrMoreExpr{
|
expr: &zeroOrMoreExpr{
|
||||||
pos: position{line: 213, col: 29, offset: 5957},
|
pos: position{line: 217, col: 29, offset: 6119},
|
||||||
expr: &ruleRefExpr{
|
expr: &ruleRefExpr{
|
||||||
pos: position{line: 213, col: 29, offset: 5957},
|
pos: position{line: 217, col: 29, offset: 6119},
|
||||||
name: "StringCharacter",
|
name: "StringCharacter",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 213, col: 46, offset: 5974},
|
pos: position{line: 217, col: 46, offset: 6136},
|
||||||
val: "\"",
|
val: "\"",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\"\"",
|
want: "\"\\\"\"",
|
||||||
|
@ -1254,17 +1281,17 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "FloatLiteral",
|
name: "FloatLiteral",
|
||||||
pos: position{line: 216, col: 1, offset: 6092},
|
pos: position{line: 220, col: 1, offset: 6254},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 216, col: 17, offset: 6108},
|
pos: position{line: 220, col: 17, offset: 6270},
|
||||||
run: (*parser).callonFloatLiteral1,
|
run: (*parser).callonFloatLiteral1,
|
||||||
expr: &seqExpr{
|
expr: &seqExpr{
|
||||||
pos: position{line: 216, col: 17, offset: 6108},
|
pos: position{line: 220, col: 17, offset: 6270},
|
||||||
exprs: []any{
|
exprs: []any{
|
||||||
&oneOrMoreExpr{
|
&oneOrMoreExpr{
|
||||||
pos: position{line: 216, col: 17, offset: 6108},
|
pos: position{line: 220, col: 17, offset: 6270},
|
||||||
expr: &charClassMatcher{
|
expr: &charClassMatcher{
|
||||||
pos: position{line: 216, col: 17, offset: 6108},
|
pos: position{line: 220, col: 17, offset: 6270},
|
||||||
val: "[0-9]",
|
val: "[0-9]",
|
||||||
ranges: []rune{'0', '9'},
|
ranges: []rune{'0', '9'},
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
|
@ -1272,15 +1299,15 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 216, col: 23, offset: 6114},
|
pos: position{line: 220, col: 23, offset: 6276},
|
||||||
val: ".",
|
val: ".",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\".\"",
|
want: "\".\"",
|
||||||
},
|
},
|
||||||
&oneOrMoreExpr{
|
&oneOrMoreExpr{
|
||||||
pos: position{line: 216, col: 26, offset: 6117},
|
pos: position{line: 220, col: 26, offset: 6279},
|
||||||
expr: &charClassMatcher{
|
expr: &charClassMatcher{
|
||||||
pos: position{line: 216, col: 26, offset: 6117},
|
pos: position{line: 220, col: 26, offset: 6279},
|
||||||
val: "[0-9]",
|
val: "[0-9]",
|
||||||
ranges: []rune{'0', '9'},
|
ranges: []rune{'0', '9'},
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
|
@ -1293,21 +1320,21 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "BooleanLiteral",
|
name: "BooleanLiteral",
|
||||||
pos: position{line: 220, col: 1, offset: 6273},
|
pos: position{line: 224, col: 1, offset: 6435},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 220, col: 19, offset: 6291},
|
pos: position{line: 224, col: 19, offset: 6453},
|
||||||
run: (*parser).callonBooleanLiteral1,
|
run: (*parser).callonBooleanLiteral1,
|
||||||
expr: &choiceExpr{
|
expr: &choiceExpr{
|
||||||
pos: position{line: 220, col: 20, offset: 6292},
|
pos: position{line: 224, col: 20, offset: 6454},
|
||||||
alternatives: []any{
|
alternatives: []any{
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 220, col: 20, offset: 6292},
|
pos: position{line: 224, col: 20, offset: 6454},
|
||||||
val: "true",
|
val: "true",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"true\"",
|
want: "\"true\"",
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 220, col: 29, offset: 6301},
|
pos: position{line: 224, col: 29, offset: 6463},
|
||||||
val: "false",
|
val: "false",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"false\"",
|
want: "\"false\"",
|
||||||
|
@ -1318,14 +1345,14 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Integer",
|
name: "Integer",
|
||||||
pos: position{line: 225, col: 1, offset: 6455},
|
pos: position{line: 229, col: 1, offset: 6617},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 225, col: 12, offset: 6466},
|
pos: position{line: 229, col: 12, offset: 6628},
|
||||||
run: (*parser).callonInteger1,
|
run: (*parser).callonInteger1,
|
||||||
expr: &oneOrMoreExpr{
|
expr: &oneOrMoreExpr{
|
||||||
pos: position{line: 225, col: 12, offset: 6466},
|
pos: position{line: 229, col: 12, offset: 6628},
|
||||||
expr: &charClassMatcher{
|
expr: &charClassMatcher{
|
||||||
pos: position{line: 225, col: 12, offset: 6466},
|
pos: position{line: 229, col: 12, offset: 6628},
|
||||||
val: "[0-9]",
|
val: "[0-9]",
|
||||||
ranges: []rune{'0', '9'},
|
ranges: []rune{'0', '9'},
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
|
@ -1336,29 +1363,29 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "StringCharacter",
|
name: "StringCharacter",
|
||||||
pos: position{line: 229, col: 1, offset: 6518},
|
pos: position{line: 233, col: 1, offset: 6680},
|
||||||
expr: &choiceExpr{
|
expr: &choiceExpr{
|
||||||
pos: position{line: 229, col: 20, offset: 6537},
|
pos: position{line: 233, col: 20, offset: 6699},
|
||||||
alternatives: []any{
|
alternatives: []any{
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 229, col: 20, offset: 6537},
|
pos: position{line: 233, col: 20, offset: 6699},
|
||||||
run: (*parser).callonStringCharacter2,
|
run: (*parser).callonStringCharacter2,
|
||||||
expr: &seqExpr{
|
expr: &seqExpr{
|
||||||
pos: position{line: 229, col: 20, offset: 6537},
|
pos: position{line: 233, col: 20, offset: 6699},
|
||||||
exprs: []any{
|
exprs: []any{
|
||||||
¬Expr{
|
¬Expr{
|
||||||
pos: position{line: 229, col: 20, offset: 6537},
|
pos: position{line: 233, col: 20, offset: 6699},
|
||||||
expr: &choiceExpr{
|
expr: &choiceExpr{
|
||||||
pos: position{line: 229, col: 22, offset: 6539},
|
pos: position{line: 233, col: 22, offset: 6701},
|
||||||
alternatives: []any{
|
alternatives: []any{
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 229, col: 22, offset: 6539},
|
pos: position{line: 233, col: 22, offset: 6701},
|
||||||
val: "\"",
|
val: "\"",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\"\"",
|
want: "\"\\\"\"",
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 229, col: 28, offset: 6545},
|
pos: position{line: 233, col: 28, offset: 6707},
|
||||||
val: "\\",
|
val: "\\",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\\\"",
|
want: "\"\\\\\"",
|
||||||
|
@ -1367,28 +1394,28 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&anyMatcher{
|
&anyMatcher{
|
||||||
line: 229, col: 34, offset: 6551,
|
line: 233, col: 34, offset: 6713,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 230, col: 5, offset: 6588},
|
pos: position{line: 234, col: 5, offset: 6750},
|
||||||
run: (*parser).callonStringCharacter9,
|
run: (*parser).callonStringCharacter9,
|
||||||
expr: &seqExpr{
|
expr: &seqExpr{
|
||||||
pos: position{line: 230, col: 5, offset: 6588},
|
pos: position{line: 234, col: 5, offset: 6750},
|
||||||
exprs: []any{
|
exprs: []any{
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 230, col: 5, offset: 6588},
|
pos: position{line: 234, col: 5, offset: 6750},
|
||||||
val: "\\",
|
val: "\\",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\\\"",
|
want: "\"\\\\\"",
|
||||||
},
|
},
|
||||||
&labeledExpr{
|
&labeledExpr{
|
||||||
pos: position{line: 230, col: 10, offset: 6593},
|
pos: position{line: 234, col: 10, offset: 6755},
|
||||||
label: "seq",
|
label: "seq",
|
||||||
expr: &ruleRefExpr{
|
expr: &ruleRefExpr{
|
||||||
pos: position{line: 230, col: 14, offset: 6597},
|
pos: position{line: 234, col: 14, offset: 6759},
|
||||||
name: "EscapeSequenceCharacter",
|
name: "EscapeSequenceCharacter",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1400,85 +1427,85 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "EscapeSequenceCharacter",
|
name: "EscapeSequenceCharacter",
|
||||||
pos: position{line: 232, col: 1, offset: 6642},
|
pos: position{line: 236, col: 1, offset: 6804},
|
||||||
expr: &labeledExpr{
|
expr: &labeledExpr{
|
||||||
pos: position{line: 232, col: 28, offset: 6669},
|
pos: position{line: 236, col: 28, offset: 6831},
|
||||||
label: "char",
|
label: "char",
|
||||||
expr: &ruleRefExpr{
|
expr: &ruleRefExpr{
|
||||||
pos: position{line: 232, col: 33, offset: 6674},
|
pos: position{line: 236, col: 33, offset: 6836},
|
||||||
name: "EscapeCharacter",
|
name: "EscapeCharacter",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "EscapeCharacter",
|
name: "EscapeCharacter",
|
||||||
pos: position{line: 234, col: 1, offset: 6691},
|
pos: position{line: 238, col: 1, offset: 6853},
|
||||||
expr: &choiceExpr{
|
expr: &choiceExpr{
|
||||||
pos: position{line: 234, col: 20, offset: 6710},
|
pos: position{line: 238, col: 20, offset: 6872},
|
||||||
alternatives: []any{
|
alternatives: []any{
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 234, col: 20, offset: 6710},
|
pos: position{line: 238, col: 20, offset: 6872},
|
||||||
val: "'",
|
val: "'",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"'\"",
|
want: "\"'\"",
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 235, col: 5, offset: 6718},
|
pos: position{line: 239, col: 5, offset: 6880},
|
||||||
val: "\"",
|
val: "\"",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\"\"",
|
want: "\"\\\"\"",
|
||||||
},
|
},
|
||||||
&litMatcher{
|
&litMatcher{
|
||||||
pos: position{line: 236, col: 5, offset: 6726},
|
pos: position{line: 240, col: 5, offset: 6888},
|
||||||
val: "\\",
|
val: "\\",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"\\\\\"",
|
want: "\"\\\\\"",
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 237, col: 5, offset: 6735},
|
pos: position{line: 241, col: 5, offset: 6897},
|
||||||
run: (*parser).callonEscapeCharacter5,
|
run: (*parser).callonEscapeCharacter5,
|
||||||
expr: &litMatcher{
|
expr: &litMatcher{
|
||||||
pos: position{line: 237, col: 5, offset: 6735},
|
pos: position{line: 241, col: 5, offset: 6897},
|
||||||
val: "b",
|
val: "b",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"b\"",
|
want: "\"b\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 238, col: 5, offset: 6764},
|
pos: position{line: 242, col: 5, offset: 6926},
|
||||||
run: (*parser).callonEscapeCharacter7,
|
run: (*parser).callonEscapeCharacter7,
|
||||||
expr: &litMatcher{
|
expr: &litMatcher{
|
||||||
pos: position{line: 238, col: 5, offset: 6764},
|
pos: position{line: 242, col: 5, offset: 6926},
|
||||||
val: "f",
|
val: "f",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"f\"",
|
want: "\"f\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 239, col: 5, offset: 6793},
|
pos: position{line: 243, col: 5, offset: 6955},
|
||||||
run: (*parser).callonEscapeCharacter9,
|
run: (*parser).callonEscapeCharacter9,
|
||||||
expr: &litMatcher{
|
expr: &litMatcher{
|
||||||
pos: position{line: 239, col: 5, offset: 6793},
|
pos: position{line: 243, col: 5, offset: 6955},
|
||||||
val: "n",
|
val: "n",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"n\"",
|
want: "\"n\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 240, col: 5, offset: 6822},
|
pos: position{line: 244, col: 5, offset: 6984},
|
||||||
run: (*parser).callonEscapeCharacter11,
|
run: (*parser).callonEscapeCharacter11,
|
||||||
expr: &litMatcher{
|
expr: &litMatcher{
|
||||||
pos: position{line: 240, col: 5, offset: 6822},
|
pos: position{line: 244, col: 5, offset: 6984},
|
||||||
val: "r",
|
val: "r",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"r\"",
|
want: "\"r\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&actionExpr{
|
&actionExpr{
|
||||||
pos: position{line: 241, col: 5, offset: 6851},
|
pos: position{line: 245, col: 5, offset: 7013},
|
||||||
run: (*parser).callonEscapeCharacter13,
|
run: (*parser).callonEscapeCharacter13,
|
||||||
expr: &litMatcher{
|
expr: &litMatcher{
|
||||||
pos: position{line: 241, col: 5, offset: 6851},
|
pos: position{line: 245, col: 5, offset: 7013},
|
||||||
val: "t",
|
val: "t",
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
want: "\"t\"",
|
want: "\"t\"",
|
||||||
|
@ -1489,25 +1516,25 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "non_escape_character",
|
name: "non_escape_character",
|
||||||
pos: position{line: 243, col: 1, offset: 6877},
|
pos: position{line: 247, col: 1, offset: 7039},
|
||||||
expr: &actionExpr{
|
expr: &actionExpr{
|
||||||
pos: position{line: 243, col: 25, offset: 6901},
|
pos: position{line: 247, col: 25, offset: 7063},
|
||||||
run: (*parser).callonnon_escape_character1,
|
run: (*parser).callonnon_escape_character1,
|
||||||
expr: &seqExpr{
|
expr: &seqExpr{
|
||||||
pos: position{line: 243, col: 25, offset: 6901},
|
pos: position{line: 247, col: 25, offset: 7063},
|
||||||
exprs: []any{
|
exprs: []any{
|
||||||
¬Expr{
|
¬Expr{
|
||||||
pos: position{line: 243, col: 25, offset: 6901},
|
pos: position{line: 247, col: 25, offset: 7063},
|
||||||
expr: &ruleRefExpr{
|
expr: &ruleRefExpr{
|
||||||
pos: position{line: 243, col: 27, offset: 6903},
|
pos: position{line: 247, col: 27, offset: 7065},
|
||||||
name: "escape_character",
|
name: "escape_character",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&labeledExpr{
|
&labeledExpr{
|
||||||
pos: position{line: 243, col: 45, offset: 6921},
|
pos: position{line: 247, col: 45, offset: 7083},
|
||||||
label: "char",
|
label: "char",
|
||||||
expr: &anyMatcher{
|
expr: &anyMatcher{
|
||||||
line: 243, col: 50, offset: 6926,
|
line: 247, col: 50, offset: 7088,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1516,11 +1543,11 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ws",
|
name: "ws",
|
||||||
pos: position{line: 246, col: 1, offset: 6965},
|
pos: position{line: 250, col: 1, offset: 7127},
|
||||||
expr: &zeroOrMoreExpr{
|
expr: &zeroOrMoreExpr{
|
||||||
pos: position{line: 246, col: 7, offset: 6971},
|
pos: position{line: 250, col: 7, offset: 7133},
|
||||||
expr: &charClassMatcher{
|
expr: &charClassMatcher{
|
||||||
pos: position{line: 246, col: 7, offset: 6971},
|
pos: position{line: 250, col: 7, offset: 7133},
|
||||||
val: "[ \\t\\n\\r]",
|
val: "[ \\t\\n\\r]",
|
||||||
chars: []rune{' ', '\t', '\n', '\r'},
|
chars: []rune{' ', '\t', '\n', '\r'},
|
||||||
ignoreCase: false,
|
ignoreCase: false,
|
||||||
|
@ -1530,11 +1557,11 @@ var g = &grammar{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "EOF",
|
name: "EOF",
|
||||||
pos: position{line: 248, col: 1, offset: 6983},
|
pos: position{line: 252, col: 1, offset: 7145},
|
||||||
expr: ¬Expr{
|
expr: ¬Expr{
|
||||||
pos: position{line: 248, col: 8, offset: 6990},
|
pos: position{line: 252, col: 8, offset: 7152},
|
||||||
expr: &anyMatcher{
|
expr: &anyMatcher{
|
||||||
line: 248, col: 9, offset: 6991,
|
line: 252, col: 9, offset: 7153,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1821,6 +1848,16 @@ func (p *parser) callonComparisonOperator7() (any, error) {
|
||||||
return p.cur.onComparisonOperator7()
|
return p.cur.onComparisonOperator7()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *current) onParameterConstant1() (any, error) {
|
||||||
|
return parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: string(c.text)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) callonParameterConstant1() (any, error) {
|
||||||
|
stack := p.vstack[len(p.vstack)-1]
|
||||||
|
_ = stack
|
||||||
|
return p.cur.onParameterConstant1()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *current) onIntegerLiteral1(number any) (any, error) {
|
func (c *current) onIntegerLiteral1(number any) (any, error) {
|
||||||
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
|
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,11 @@ ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
|
||||||
return string(c.text), nil
|
return string(c.text), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral
|
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant
|
||||||
|
|
||||||
|
ParameterConstant <- "@" Identifier {
|
||||||
|
return parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: string(c.text)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
IntegerLiteral <- number:Integer {
|
IntegerLiteral <- number:Integer {
|
||||||
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
|
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
|
||||||
|
|
|
@ -233,7 +233,8 @@ func Test_Parse(t *testing.T) {
|
||||||
WHERE c.boolean=true
|
WHERE c.boolean=true
|
||||||
AND c.integer=1
|
AND c.integer=1
|
||||||
AND c.float=6.9
|
AND c.float=6.9
|
||||||
AND c.string="hello"`,
|
AND c.string="hello"
|
||||||
|
AND c.param=@param_id1`,
|
||||||
parsers.SelectStmt{
|
parsers.SelectStmt{
|
||||||
SelectItems: []parsers.SelectItem{{Path: []string{"c", "id"}, Alias: ""}},
|
SelectItems: []parsers.SelectItem{{Path: []string{"c", "id"}, Alias: ""}},
|
||||||
Table: parsers.Table{Value: "c"},
|
Table: parsers.Table{Value: "c"},
|
||||||
|
@ -241,22 +242,27 @@ func Test_Parse(t *testing.T) {
|
||||||
Expressions: []interface{}{
|
Expressions: []interface{}{
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "boolean"}},
|
Left: parsers.SelectItem{Path: []string{"c", "boolean"}},
|
||||||
Right: parsers.Constant{Type: 3, Value: true},
|
Right: parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: true},
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "integer"}},
|
Left: parsers.SelectItem{Path: []string{"c", "integer"}},
|
||||||
Right: parsers.Constant{Type: 1, Value: 1},
|
Right: parsers.Constant{Type: parsers.ConstantTypeInteger, Value: 1},
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "float"}},
|
Left: parsers.SelectItem{Path: []string{"c", "float"}},
|
||||||
Right: parsers.Constant{Type: 2, Value: 6.9},
|
Right: parsers.Constant{Type: parsers.ConstantTypeFloat, Value: 6.9},
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
parsers.ComparisonExpression{
|
parsers.ComparisonExpression{
|
||||||
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
||||||
Right: parsers.Constant{Type: 0, Value: "hello"},
|
Right: parsers.Constant{Type: parsers.ConstantTypeString, Value: "hello"},
|
||||||
|
Operation: "=",
|
||||||
|
},
|
||||||
|
parsers.ComparisonExpression{
|
||||||
|
Left: parsers.SelectItem{Path: []string{"c", "param"}},
|
||||||
|
Right: parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: "@param_id1"},
|
||||||
Operation: "=",
|
Operation: "=",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,7 +13,7 @@ func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
||||||
// Iterate over each row in the data
|
// Iterate over each row in the data
|
||||||
for _, row := range data {
|
for _, row := range data {
|
||||||
// Check if the row satisfies the filter conditions
|
// Check if the row satisfies the filter conditions
|
||||||
if evaluateFilters(query.Filters, row) {
|
if evaluateFilters(query.Filters, query.Parameters, row) {
|
||||||
result = append(result, selectRow(query.SelectItems, row))
|
result = append(result, selectRow(query.SelectItems, row))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,15 +53,15 @@ func selectRow(selectItems []parsers.SelectItem, row RowType) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to evaluate filter conditions recursively
|
// Helper function to evaluate filter conditions recursively
|
||||||
func evaluateFilters(expr ExpressionType, row RowType) bool {
|
func evaluateFilters(expr ExpressionType, Parameters map[string]interface{}, row RowType) bool {
|
||||||
if expr == nil {
|
if expr == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typedValue := expr.(type) {
|
switch typedValue := expr.(type) {
|
||||||
case parsers.ComparisonExpression:
|
case parsers.ComparisonExpression:
|
||||||
leftValue := getExpressionParameterValue(typedValue.Left, row)
|
leftValue := getExpressionParameterValue(typedValue.Left, Parameters, row)
|
||||||
rightValue := getExpressionParameterValue(typedValue.Right, row)
|
rightValue := getExpressionParameterValue(typedValue.Right, Parameters, row)
|
||||||
|
|
||||||
switch typedValue.Operation {
|
switch typedValue.Operation {
|
||||||
case "=":
|
case "=":
|
||||||
|
@ -71,7 +71,7 @@ func evaluateFilters(expr ExpressionType, row RowType) bool {
|
||||||
case parsers.LogicalExpression:
|
case parsers.LogicalExpression:
|
||||||
var result bool
|
var result bool
|
||||||
for i, expression := range typedValue.Expressions {
|
for i, expression := range typedValue.Expressions {
|
||||||
expressionResult := evaluateFilters(expression, row)
|
expressionResult := evaluateFilters(expression, Parameters, row)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
result = expressionResult
|
result = expressionResult
|
||||||
}
|
}
|
||||||
|
@ -124,11 +124,22 @@ func getFieldValue(field parsers.SelectItem, row RowType) interface{} {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExpressionParameterValue(parameter interface{}, row RowType) interface{} {
|
func getExpressionParameterValue(
|
||||||
|
parameter interface{},
|
||||||
|
Parameters map[string]interface{},
|
||||||
|
row RowType,
|
||||||
|
) interface{} {
|
||||||
switch typedParameter := parameter.(type) {
|
switch typedParameter := parameter.(type) {
|
||||||
case parsers.SelectItem:
|
case parsers.SelectItem:
|
||||||
return getFieldValue(typedParameter, row)
|
return getFieldValue(typedParameter, row)
|
||||||
case parsers.Constant:
|
case parsers.Constant:
|
||||||
|
if typedParameter.Type == parsers.ConstantTypeParameterConstant &&
|
||||||
|
Parameters != nil {
|
||||||
|
if key, ok := typedParameter.Value.(string); ok {
|
||||||
|
return Parameters[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return typedParameter.Value
|
return typedParameter.Value
|
||||||
}
|
}
|
||||||
// TODO: Handle error
|
// TODO: Handle error
|
||||||
|
|
|
@ -175,6 +175,30 @@ func Test_Execute(t *testing.T) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute SELECT with WHERE condition with defined parameter constant", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{Path: []string{"c", "id"}},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
Filters: parsers.ComparisonExpression{
|
||||||
|
Operation: "=",
|
||||||
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
||||||
|
Right: parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: "@param_id"},
|
||||||
|
},
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"@param_id": "456",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "456"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Should execute SELECT with multiple WHERE conditions", func(t *testing.T) {
|
t.Run("Should execute SELECT with multiple WHERE conditions", func(t *testing.T) {
|
||||||
testQueryExecute(
|
testQueryExecute(
|
||||||
t,
|
t,
|
||||||
|
|
Loading…
Reference in New Issue