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"
|
"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(
|
pager := collectionClient.NewQueryItemsPager(
|
||||||
query,
|
query,
|
||||||
azcosmos.PartitionKey{},
|
azcosmos.PartitionKey{},
|
||||||
&azcosmos.QueryOptions{})
|
&azcosmos.QueryOptions{})
|
||||||
|
|
||||||
context := context.TODO()
|
context := context.TODO()
|
||||||
items := make([]map[string]interface{}, 0)
|
items := make([]interface{}, 0)
|
||||||
|
|
||||||
for pager.More() {
|
for pager.More() {
|
||||||
response, err := pager.NextPage(context)
|
response, err := pager.NextPage(context)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
for _, bytes := range response.Items {
|
for _, bytes := range response.Items {
|
||||||
var item map[string]interface{}
|
var item interface{}
|
||||||
err := json.Unmarshal(bytes, &item)
|
err := json.Unmarshal(bytes, &item)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
@ -70,9 +70,19 @@ 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",
|
||||||
[]map[string]interface{}{
|
[]interface{}{
|
||||||
{"id": "12345", "pk": "123"},
|
map[string]interface{}{"id": "12345", "pk": "123"},
|
||||||
{"id": "67890", "pk": "456"},
|
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
|
`select c.id
|
||||||
FROM c
|
FROM c
|
||||||
WHERE c.isCool=true`,
|
WHERE c.isCool=true`,
|
||||||
[]map[string]interface{}{
|
[]interface{}{
|
||||||
{"id": "67890"},
|
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
|
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 {
|
func joinStrings(array []interface{}) string {
|
||||||
var stringsArray []string
|
var stringsArray []string
|
||||||
for _, elem := range array {
|
for _, elem := range array {
|
||||||
|
@ -101,11 +114,17 @@ TableName <- key:Identifier {
|
||||||
return parsers.Table{Value: key.(string)}, nil
|
return parsers.Table{Value: key.(string)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectItem <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)*
|
SelectArray <- "[" ws columns:ColumnList ws "]" asClause:AsClause? {
|
||||||
asClause:(ws "AS" ws alias:Identifier { return alias, nil })? {
|
return makeSelectArray(columns, asClause)
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectItem <- SelectArray / name:Identifier path:(DotFieldAccess / ArrayFieldAccess)*
|
||||||
|
asClause:AsClause? {
|
||||||
return makeSelectItem(name, path, asClause, parsers.SelectItemTypeField)
|
return makeSelectItem(name, path, asClause, parsers.SelectItemTypeField)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsClause <- ws As ws alias:Identifier { return alias, nil }
|
||||||
|
|
||||||
DotFieldAccess <- "." id:Identifier {
|
DotFieldAccess <- "." id:Identifier {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
@ -136,6 +155,8 @@ ComparisonExpression <- left:(Literal / SelectItem) ws op:ComparisonOperator ws
|
||||||
|
|
||||||
Select <- ("select" / "SELECT")
|
Select <- ("select" / "SELECT")
|
||||||
|
|
||||||
|
As <- ("as" / "AS")
|
||||||
|
|
||||||
From <- ("from" / "FROM")
|
From <- ("from" / "FROM")
|
||||||
|
|
||||||
Where <- ("where" / "WHERE")
|
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) {
|
t.Run("Should parse SELECT with single WHERE condition", func(t *testing.T) {
|
||||||
testQueryParse(
|
testQueryParse(
|
||||||
t,
|
t,
|
||||||
|
|
|
@ -84,6 +84,14 @@ func evaluateFilters(expr ExpressionType, row RowType) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFieldValue(field parsers.SelectItem, row RowType) interface{} {
|
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
|
value := row
|
||||||
for _, pathSegment := range field.Path[1:] {
|
for _, pathSegment := range field.Path[1:] {
|
||||||
if nestedValue, ok := value.(map[string]interface{}); ok {
|
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) {
|
t.Run("Should execute SELECT with single WHERE condition", func(t *testing.T) {
|
||||||
testQueryExecute(
|
testQueryExecute(
|
||||||
t,
|
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