Compare commits

...

2 Commits

Author SHA1 Message Date
Pijus Kamandulis
f5b8453995 Support patch operations 'set' and 'incr' #7 2024-12-25 23:32:50 +02:00
Pijus Kamandulis
928ca29fe4 Support parameter in bracket #8 2024-12-25 21:28:42 +02:00
9 changed files with 1416 additions and 1312 deletions

View File

@ -6,11 +6,11 @@ import (
"net/http"
"strconv"
jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/gin-gonic/gin"
"github.com/pikami/cosmium/internal/constants"
"github.com/pikami/cosmium/internal/logger"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
jsonpatch "github.com/pikami/json-patch/v5"
)
func (h *Handlers) GetAllDocuments(c *gin.Context) {

View File

@ -147,6 +147,21 @@ func Test_Documents(t *testing.T) {
)
})
t.Run("Should query document with query parameters as accessor", func(t *testing.T) {
testCosmosQuery(t, collectionClient,
`select c.id
FROM c
WHERE c[@param]="67890"
ORDER BY c.id`,
[]azcosmos.QueryParameter{
{Name: "@param", Value: "id"},
},
[]interface{}{
map[string]interface{}{"id": "67890"},
},
)
})
t.Run("Should query array accessor", func(t *testing.T) {
testCosmosQuery(t, collectionClient,
`SELECT c.id,
@ -220,11 +235,14 @@ func Test_Documents_Patch(t *testing.T) {
t.Run("Should PATCH document", func(t *testing.T) {
context := context.TODO()
expectedData := map[string]interface{}{"id": "67890", "pk": "456", "newField": "newValue"}
expectedData := map[string]interface{}{"id": "67890", "pk": "666", "newField": "newValue", "incr": 15., "setted": "isSet"}
patch := azcosmos.PatchOperations{}
patch.AppendAdd("/newField", "newValue")
patch.AppendIncrement("/incr", 15)
patch.AppendRemove("/isCool")
patch.AppendReplace("/pk", "666")
patch.AppendSet("/setted", "isSet")
itemResponse, err := collectionClient.PatchItem(
context,
@ -237,13 +255,15 @@ func Test_Documents_Patch(t *testing.T) {
)
assert.Nil(t, err)
var itemResponseBody map[string]string
var itemResponseBody map[string]interface{}
json.Unmarshal(itemResponse.Value, &itemResponseBody)
assert.Equal(t, expectedData["id"], itemResponseBody["id"])
assert.Equal(t, expectedData["pk"], itemResponseBody["pk"])
assert.Empty(t, itemResponseBody["isCool"])
assert.Equal(t, expectedData["newField"], itemResponseBody["newField"])
assert.Equal(t, expectedData["incr"], itemResponseBody["incr"])
assert.Equal(t, expectedData["setted"], itemResponseBody["setted"])
})
t.Run("Should not allow to PATCH document ID", func(t *testing.T) {

2
go.mod
View File

@ -5,9 +5,9 @@ go 1.22.0
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.6
github.com/evanphx/json-patch/v5 v5.9.0
github.com/gin-gonic/gin v1.10.0
github.com/google/uuid v1.6.0
github.com/pikami/json-patch/v5 v5.9.2
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
)

4
go.sum
View File

@ -22,8 +22,6 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -66,6 +64,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pikami/json-patch/v5 v5.9.2 h1:ciTlocWccYVE3DEa45dsMm02c/tOvcaBY7PpEUNZhrU=
github.com/pikami/json-patch/v5 v5.9.2/go.mod h1:eJIScZ4xgf2aBHLi2UMzYtjlWESUBDOBf7EAx3JW0nI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

File diff suppressed because it is too large Load Diff

View File

@ -325,6 +325,7 @@ DotFieldAccess <- "." id:Identifier {
ArrayFieldAccess <- "[\"" id:Identifier "\"]" { return id, nil }
/ "[" id:Integer "]" { return strconv.Itoa(id.(int)), nil }
/ "[" id:ParameterConstant "]" { return id.(parsers.Constant).Value.(string), nil }
Identifier <- [a-zA-Z_][a-zA-Z0-9_]* {
return string(c.text), nil

View File

@ -22,6 +22,20 @@ func Test_Parse_Select(t *testing.T) {
)
})
t.Run("Should parse SELECT with query parameters as accessor", func(t *testing.T) {
testQueryParse(
t,
`SELECT c.id, c[@param] FROM c`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
{Path: []string{"c", "@param"}},
},
Table: parsers.Table{Value: "c"},
},
)
})
t.Run("Should parse SELECT DISTINCT", func(t *testing.T) {
testQueryParse(
t,

View File

@ -317,6 +317,10 @@ func (r rowContext) applyProjection(selectItems []parsers.SelectItem) RowType {
} else {
destinationName = fmt.Sprintf("$%d", index+1)
}
if destinationName[0] == '@' {
destinationName = r.parameters[destinationName].(string)
}
}
row[destinationName] = r.resolveSelectItem(selectItem)
@ -572,6 +576,9 @@ func (r rowContext) selectItem_SelectItemTypeField(selectItem parsers.SelectItem
if len(selectItem.Path) > 1 {
for _, pathSegment := range selectItem.Path[1:] {
if pathSegment[0] == '@' {
pathSegment = r.parameters[pathSegment].(string)
}
switch nestedValue := value.(type) {
case map[string]interface{}:

View File

@ -35,6 +35,29 @@ func Test_Execute_Select(t *testing.T) {
)
})
t.Run("Should execute SELECT with query parameters as accessor", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
{Path: []string{"c", "@param"}},
},
Table: parsers.Table{Value: "c"},
Parameters: map[string]interface{}{
"@param": "pk",
},
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"id": "12345", "pk": 123},
map[string]interface{}{"id": "67890", "pk": 456},
map[string]interface{}{"id": "456", "pk": 456},
map[string]interface{}{"id": "123", "pk": 456},
},
)
})
t.Run("Should execute SELECT DISTINCT", func(t *testing.T) {
testQueryExecute(
t,