mirror of https://github.com/pikami/cosmium.git
Implement executing queries using API
This commit is contained in:
parent
bdf9970ce6
commit
88526dcdcc
|
@ -77,10 +77,17 @@ func DocumentsPost(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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))
|
||||||
|
if status != repositories.StatusOk {
|
||||||
|
// TODO: Currently we return everything if the query fails
|
||||||
GetAllDocuments(c)
|
GetAllDocuments(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusOK, gin.H{"_rid": "", "Documents": docs, "_count": len(docs)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if requestBody["id"] == "" {
|
if requestBody["id"] == "" {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"message": "BadRequest"})
|
c.JSON(http.StatusBadRequest, gin.H{"message": "BadRequest"})
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package tests_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
|
||||||
|
"github.com/pikami/cosmium/internal/repositories"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testCosmosQuery(t *testing.T, collectionClient *azcosmos.ContainerClient, query string, expectedData []map[string]interface{}) {
|
||||||
|
pager := collectionClient.NewQueryItemsPager(
|
||||||
|
query,
|
||||||
|
azcosmos.PartitionKey{},
|
||||||
|
&azcosmos.QueryOptions{})
|
||||||
|
|
||||||
|
context := context.TODO()
|
||||||
|
items := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
for pager.More() {
|
||||||
|
response, err := pager.NextPage(context)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
for _, bytes := range response.Items {
|
||||||
|
var item map[string]interface{}
|
||||||
|
err := json.Unmarshal(bytes, &item)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, len(expectedData), len(items))
|
||||||
|
if !reflect.DeepEqual(items, expectedData) {
|
||||||
|
t.Errorf("executed query does not match expected data.\nExpected: %+v\nGot: %+v", expectedData, items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Documents(t *testing.T) {
|
||||||
|
repositories.CreateCollection(testDatabaseName, repositories.Collection{
|
||||||
|
ID: testCollectionName,
|
||||||
|
PartitionKey: struct {
|
||||||
|
Paths []string "json:\"paths\""
|
||||||
|
Kind string "json:\"kind\""
|
||||||
|
Version int "json:\"Version\""
|
||||||
|
}{
|
||||||
|
Paths: []string{"/pk"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
repositories.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "12345", "pk": "123", "isCool": false})
|
||||||
|
repositories.CreateDocument(testDatabaseName, testCollectionName, map[string]interface{}{"id": "67890", "pk": "456", "isCool": true})
|
||||||
|
|
||||||
|
ts := runTestServer()
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client, err := azcosmos.NewClientFromConnectionString(
|
||||||
|
fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s", ts.URL, "asas"),
|
||||||
|
&azcosmos.ClientOptions{},
|
||||||
|
)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
collectionClient, err := client.NewContainer(testDatabaseName, testCollectionName)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
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"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should query document with single WHERE condition", func(t *testing.T) {
|
||||||
|
testCosmosQuery(t, collectionClient,
|
||||||
|
`select c.id
|
||||||
|
FROM c
|
||||||
|
WHERE c.isCool=true`,
|
||||||
|
[]map[string]interface{}{
|
||||||
|
{"id": "67890"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,13 @@
|
||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
"github.com/pikami/cosmium/parsers/nosql"
|
||||||
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
)
|
||||||
|
|
||||||
var documents = []Document{}
|
var documents = []Document{}
|
||||||
|
|
||||||
|
@ -76,6 +83,12 @@ func CreateDocument(databaseId string, collectionId string, document map[string]
|
||||||
for _, part := range strings.Split(path, "/") {
|
for _, part := range strings.Split(path, "/") {
|
||||||
val = document[part]
|
val = document[part]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val == nil {
|
||||||
|
val = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle non-string partition keys
|
||||||
partitionKeyValue = append(partitionKeyValue, val.(string))
|
partitionKeyValue = append(partitionKeyValue, val.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,3 +101,23 @@ func CreateDocument(databaseId string, collectionId string, document map[string]
|
||||||
|
|
||||||
return StatusOk
|
return StatusOk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExecuteQueryDocuments(databaseId string, collectionId string, query string) ([]memoryexecutor.RowType, RepositoryStatus) {
|
||||||
|
parsedQuery, err := nosql.Parse("", []byte(query))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to parse query: %s\nerr: %v", query, err)
|
||||||
|
return nil, BadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionDocuments, status := GetAllDocuments(databaseId, collectionId)
|
||||||
|
if status != StatusOk {
|
||||||
|
return nil, status
|
||||||
|
}
|
||||||
|
|
||||||
|
covDocs := make([]memoryexecutor.RowType, 0)
|
||||||
|
for _, doc := range collectionDocuments {
|
||||||
|
covDocs = append(covDocs, map[string]interface{}(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
return memoryexecutor.Execute(parsedQuery.(parsers.SelectStmt), covDocs), StatusOk
|
||||||
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func Test_Parse(t *testing.T) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Shoul 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,
|
||||||
`select c.id
|
`select c.id
|
||||||
|
|
|
@ -8,7 +8,7 @@ type RowType interface{}
|
||||||
type ExpressionType interface{}
|
type ExpressionType interface{}
|
||||||
|
|
||||||
func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
func Execute(query parsers.SelectStmt, data []RowType) []RowType {
|
||||||
var result []RowType
|
result := make([]RowType, 0)
|
||||||
|
|
||||||
// Iterate over each row in the data
|
// Iterate over each row in the data
|
||||||
for _, row := range data {
|
for _, row := range data {
|
||||||
|
|
|
@ -17,7 +17,7 @@ func testQueryExecute(
|
||||||
result := memoryexecutor.Execute(query, data)
|
result := memoryexecutor.Execute(query, data)
|
||||||
|
|
||||||
if !reflect.DeepEqual(result, expectedData) {
|
if !reflect.DeepEqual(result, expectedData) {
|
||||||
t.Errorf("parsed query does not match expected structure.\nExpected: %+v\nGot: %+v", expectedData, result)
|
t.Errorf("execution result does not match expected data.\nExpected: %+v\nGot: %+v", expectedData, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue