Skip to content

Commit

Permalink
ING-903: Added support for touch operations to Data API.
Browse files Browse the repository at this point in the history
  • Loading branch information
Brett Lawson committed Sep 24, 2024
1 parent f12ba4e commit 5f00784
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 0 deletions.
58 changes: 58 additions & 0 deletions dataapiv1/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,64 @@ paths:
$ref: '#/components/responses/ServiceUnavailable'
'504':
$ref: '#/components/responses/GatewayTimeout'
'/v1.alpha/buckets/{bucketName}/scopes/{scopeName}/collections/{collectionName}/documents/{documentKey}/touch':
parameters:
- $ref: '#/components/parameters/AuthorizationHeader'
- $ref: '#/components/parameters/BucketName'
- $ref: '#/components/parameters/ScopeName'
- $ref: '#/components/parameters/CollectionName'
- $ref: '#/components/parameters/DocumentKey'
post:
operationId: touchDocument
tags:
- Expiry Operations
parameters:
- $ref: '#/components/parameters/AcceptEncodingHeader'
requestBody:
required: true
content:
'application/json':
schema:
type: object
properties:
expiry:
description: The new expiry to set for the document, specified as an ISO8601 string.
type: string
returnContent:
description: Specifies whether the documents contents should be returned in the response.
type: boolean
responses:
'200':
description: Successful updated the expiry of the document and is returning the content of the document.
headers:
Content-Encoding:
$ref: "#/components/headers/ContentEncoding"
ETag:
$ref: "#/components/headers/ETag"
X-CB-Flags:
$ref: "#/components/headers/DocumentFlags"
content:
'*':
schema:
type: string
format: binary
'202':
description: Successful updated the expiry of the document but is not returning the content of the document.
headers:
ETag:
$ref: "#/components/headers/ETag"
'400':
$ref: '#/components/responses/BadRequest'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
'504':
$ref: '#/components/responses/GatewayTimeout'
components:
securitySchemes:
BasicAuth:
Expand Down
111 changes: 111 additions & 0 deletions gateway/dapiimpl/server_v1/dataapi_touch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package server_v1

import (
"bytes"
"context"
"errors"

"github.com/couchbase/gocbcorex"
"github.com/couchbase/gocbcorex/memdx"
"github.com/couchbase/stellar-gateway/dataapiv1"
)

func (s *DataApiServer) TouchDocument(
ctx context.Context, in dataapiv1.TouchDocumentRequestObject,
) (dataapiv1.TouchDocumentResponseObject, error) {
bucketAgent, oboUser, errSt := s.authHandler.GetMemdOboAgent(ctx, in.Params.Authorization, in.BucketName)
if errSt != nil {
return nil, errSt.Err()
}

key, errSt := s.parseKey(in.DocumentKey)
if errSt != nil {
return nil, errSt.Err()
}

var newExpiry uint32
if in.Body.Expiry != nil {
expiry, errSt := httpTimeToGocbcorexExpiry(*in.Body.Expiry)
if errSt != nil {
return nil, errSt.Err()
}

newExpiry = expiry
}

if in.Body.ReturnContent == nil || !*in.Body.ReturnContent {
var opts gocbcorex.TouchOptions
opts.OnBehalfOf = oboUser
opts.ScopeName = in.ScopeName
opts.CollectionName = in.CollectionName
opts.Key = key
opts.Expiry = newExpiry

result, err := bucketAgent.Touch(ctx, &opts)
if err != nil {
if errors.Is(err, memdx.ErrDocLocked) {
return nil, s.errorHandler.NewDocLockedStatus(err, in.BucketName, in.ScopeName, in.CollectionName, in.DocumentKey).Err()
} else if errors.Is(err, memdx.ErrDocNotFound) {
return nil, s.errorHandler.NewDocMissingStatus(err, in.BucketName, in.ScopeName, in.CollectionName, in.DocumentKey).Err()
} else if errors.Is(err, memdx.ErrUnknownCollectionName) {
return nil, s.errorHandler.NewCollectionMissingStatus(err, in.BucketName, in.ScopeName, in.CollectionName).Err()
} else if errors.Is(err, memdx.ErrUnknownScopeName) {
return nil, s.errorHandler.NewScopeMissingStatus(err, in.BucketName, in.ScopeName).Err()
} else if errors.Is(err, memdx.ErrAccessError) {
return nil, s.errorHandler.NewCollectionNoWriteAccessStatus(err, in.BucketName, in.ScopeName, in.CollectionName).Err()
}
return nil, s.errorHandler.NewGenericStatus(err).Err()
}

return dataapiv1.TouchDocument202Response{
Headers: dataapiv1.TouchDocument202ResponseHeaders{
ETag: casToHttpEtag(result.Cas),
},
}, nil
} else {
var opts gocbcorex.GetAndTouchOptions
opts.OnBehalfOf = oboUser
opts.ScopeName = in.ScopeName
opts.CollectionName = in.CollectionName
opts.Key = key
opts.Expiry = newExpiry

result, err := bucketAgent.GetAndTouch(ctx, &opts)
if err != nil {
if errors.Is(err, memdx.ErrDocLocked) {
return nil, s.errorHandler.NewDocLockedStatus(err, in.BucketName, in.ScopeName, in.CollectionName, in.DocumentKey).Err()
} else if errors.Is(err, memdx.ErrDocNotFound) {
return nil, s.errorHandler.NewDocMissingStatus(err, in.BucketName, in.ScopeName, in.CollectionName, in.DocumentKey).Err()
} else if errors.Is(err, memdx.ErrUnknownCollectionName) {
return nil, s.errorHandler.NewCollectionMissingStatus(err, in.BucketName, in.ScopeName, in.CollectionName).Err()
} else if errors.Is(err, memdx.ErrUnknownScopeName) {
return nil, s.errorHandler.NewScopeMissingStatus(err, in.BucketName, in.ScopeName).Err()
} else if errors.Is(err, memdx.ErrAccessError) {
return nil, s.errorHandler.NewCollectionNoWriteAccessStatus(err, in.BucketName, in.ScopeName, in.CollectionName).Err()
}
return nil, s.errorHandler.NewGenericStatus(err).Err()
}

resp := dataapiv1.TouchDocument200AsteriskResponse{
Headers: dataapiv1.TouchDocument200ResponseHeaders{
ETag: casToHttpEtag(result.Cas),
XCBFlags: uint32(result.Flags),
},
}

contentType := flagsToHttpContentType(result.Flags)

contentEncoding, respValue, errSt :=
CompressHandler{}.MaybeCompressContent(result.Value, 0, in.Params.AcceptEncoding)
if errSt != nil {
return nil, errSt.Err()
}

resp.ContentType = contentType
resp.Headers.ContentEncoding = contentEncoding
resp.Body = bytes.NewReader(respValue)
resp.ContentLength = int64(len(respValue))

return resp, nil
}
}

0 comments on commit 5f00784

Please sign in to comment.