mirror of https://github.com/pikami/cosmium.git
Added support for array selects
This commit is contained in:
parent
e89f2e5611
commit
5d2b21dc46
|
@ -13,21 +13,21 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, query string, expectedData []map[string]interface{}) {
|
||||
func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, query string, expectedData []interface{}) {
|
||||
pager := collectionClient.NewQueryItemsPager(
|
||||
query,
|
||||
azcosmos.PartitionKey{},
|
||||
&azcosmos.QueryOptions{})
|
||||
|
||||
context := context.TODO()
|
||||
items := make([]map[string]interface{}, 0)
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for pager.More() {
|
||||
response, err := pager.NextPage(context)
|
||||
assert.Nil(t, err)
|
||||
|
||||
for _, bytes := range response.Items {
|
||||
var item map[string]interface{}
|
||||
var item interface{}
|
||||
err := json.Unmarshal(bytes, &item)
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
@ -70,9 +70,19 @@ func Test_Documents(t *testing.T) {
|
|||
t.Run("Should query document", func(t *testing.T) {
|
||||
testCosmosQuery(t, collectionClient,
|
||||
"SELECT c.id, c[\"pk\"] FROM c",
|
||||
[]map[string]interface{}{
|
||||
{"id": "12345", "pk": "123"},
|
||||
{"id": "67890", "pk": "456"},
|
||||
[]interface{}{
|
||||
map[string]interface{}{"id": "12345", "pk": "123"},
|
||||
map[string]interface{}{"id": "67890", "pk": "456"},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("Should query VALUE array", func(t *testing.T) {
|
||||
testCosmosQuery(t, collectionClient,
|
||||
"SELECT VALUE [c.id, c[\"pk\"]] FROM c",
|
||||
[]interface{}{
|
||||
[]interface{}{"12345", "123"},
|
||||
[]interface{}{"67890", "456"},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -82,8 +92,8 @@ func Test_Documents(t *testing.T) {
|
|||
`select c.id
|
||||
FROM c
|
||||
WHERE c.isCool=true`,
|
||||
[]map[string]interface{}{
|
||||
{"id": "67890"},
|
||||
[]interface{}{
|
||||
map[string]interface{}{"id": "67890"},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,6 +49,19 @@ func makeColumnList(column interface{}, other_columns interface{}) ([]parsers.Se
|
|||
return columnList, nil
|
||||
}
|
||||
|
||||
func makeSelectArray(columns interface{}, asClause interface{}) (parsers.SelectItem, error) {
|
||||
selectItem := parsers.SelectItem{
|
||||
SelectItems: columns.([]parsers.SelectItem),
|
||||
Type: parsers.SelectItemTypeArray,
|
||||
}
|
||||
|
||||
if aliasValue, ok := asClause.(string); ok {
|
||||
selectItem.Alias = aliasValue
|
||||
}
|
||||
|
||||
return selectItem, nil
|
||||
}
|
||||
|
||||
func joinStrings(array []interface{}) string {
|
||||
var stringsArray []string
|
||||
for _, elem := range array {
|
||||
|
@ -101,11 +114,17 @@ TableName <- key:Identifier {
|
|||
return parsers.Table{Value: key.(string)}, nil
|
||||
}
|
||||
|
||||
SelectItem <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)*
|
||||
asClause:(ws "AS" ws alias:Identifier { return alias, nil })? {
|
||||
SelectArray <- "[" ws columns:ColumnList ws "]" asClause:AsClause? {
|
||||
return makeSelectArray(columns, asClause)
|
||||
}
|
||||
|
||||
SelectItem <- SelectArray / name:Identifier path:(DotFieldAccess / ArrayFieldAccess)*
|
||||
asClause:AsClause? {
|
||||
return makeSelectItem(name, path, asClause, parsers.SelectItemTypeField)
|
||||
}
|
||||
|
||||
AsClause <- ws As ws alias:Identifier { return alias, nil }
|
||||
|
||||
DotFieldAccess <- "." id:Identifier {
|
||||
return id, nil
|
||||
}
|
||||
|
@ -136,6 +155,8 @@ ComparisonExpression <- left:(Literal / SelectItem) ws op:ComparisonOperator ws
|
|||
|
||||
Select <- ("select" / "SELECT")
|
||||
|
||||
As <- ("as" / "AS")
|
||||
|
||||
From <- ("from" / "FROM")
|
||||
|
||||
Where <- ("where" / "WHERE")
|
||||
|
|
|
@ -65,6 +65,26 @@ func Test_Parse(t *testing.T) {
|
|||
)
|
||||
})
|
||||
|
||||
t.Run("Should parse SELECT array", func(t *testing.T) {
|
||||
testQueryParse(
|
||||
t,
|
||||
`SELECT [c.id, c.pk] as arr FROM c`,
|
||||
parsers.SelectStmt{
|
||||
SelectItems: []parsers.SelectItem{
|
||||
{
|
||||
Alias: "arr",
|
||||
Type: parsers.SelectItemTypeArray,
|
||||
SelectItems: []parsers.SelectItem{
|
||||
{Path: []string{"c", "id"}},
|
||||
{Path: []string{"c", "pk"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Table: parsers.Table{Value: "c"},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("Should parse SELECT with single WHERE condition", func(t *testing.T) {
|
||||
testQueryParse(
|
||||
t,
|
||||
|
|
|
@ -84,6 +84,14 @@ func evaluateFilters(expr ExpressionType, row RowType) bool {
|
|||
}
|
||||
|
||||
func getFieldValue(field parsers.SelectItem, row RowType) interface{} {
|
||||
if field.Type == parsers.SelectItemTypeArray {
|
||||
arrayValue := make([]interface{}, 0)
|
||||
for _, selectItem := range field.SelectItems {
|
||||
arrayValue = append(arrayValue, getFieldValue(selectItem, row))
|
||||
}
|
||||
return arrayValue
|
||||
}
|
||||
|
||||
value := row
|
||||
for _, pathSegment := range field.Path[1:] {
|
||||
if nestedValue, ok := value.(map[string]interface{}); ok {
|
||||
|
|
|
@ -62,6 +62,30 @@ func Test_Execute(t *testing.T) {
|
|||
)
|
||||
})
|
||||
|
||||
t.Run("Should execute SELECT array", func(t *testing.T) {
|
||||
testQueryExecute(
|
||||
t,
|
||||
parsers.SelectStmt{
|
||||
SelectItems: []parsers.SelectItem{
|
||||
{
|
||||
Alias: "arr",
|
||||
Type: parsers.SelectItemTypeArray,
|
||||
SelectItems: []parsers.SelectItem{
|
||||
{Path: []string{"c", "id"}},
|
||||
{Path: []string{"c", "pk"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Table: parsers.Table{Value: "c"},
|
||||
},
|
||||
mockData,
|
||||
[]memoryexecutor.RowType{
|
||||
map[string]interface{}{"arr": []interface{}{"12345", 123}},
|
||||
map[string]interface{}{"arr": []interface{}{"67890", 456}},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("Should execute SELECT with single WHERE condition", func(t *testing.T) {
|
||||
testQueryExecute(
|
||||
t,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
### Create collection
|
||||
|
||||
POST https://localhost:8081/dbs/db1/colls
|
||||
Content-Type: application/json
|
||||
|
||||
{"id":"test1", "partitionKey":{"paths":["/pk"],"kind":"Hash","version":2}}
|
||||
|
||||
### Insert document
|
||||
|
||||
POST https://localhost:8081/dbs/db1/colls/test/docs
|
||||
Content-Type: application/json
|
||||
|
||||
{"id":"1","_pk":"123","isCool":true}
|
||||
|
||||
### Get all documents
|
||||
|
||||
GET https://localhost:8081/dbs/db1/colls/test/docs
|
||||
|
||||
### Query documents
|
||||
|
||||
POST https://localhost:8081/dbs/db1/colls/test/docs
|
||||
Content-Type: application/json
|
||||
|
||||
{"query":"SELECT c.id, c.isCool AS cool FROM c WHERE c.isCool = false"}
|
Loading…
Reference in New Issue