This commit is contained in:
Luís Murta 2024-06-01 09:11:42 +01:00
parent a6a350c901
commit a7cf8fd062
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
5 changed files with 156 additions and 18 deletions

View File

@ -73,6 +73,21 @@ paths:
$ref: "#/components/schemas/Transaction" $ref: "#/components/schemas/Transaction"
"400": "400":
description: Transaction not created description: Transaction not created
put:
summary: Update an existing transaction
operationId: updateTransaction
requestBody:
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Transaction"
- required:
- id
responses:
"204":
description: Transaction updated successfully
/transaction/{transactionId}: /transaction/{transactionId}:
get: get:

View File

@ -83,11 +83,46 @@ func (server *ServerImpl) CreateTransaction(ctx echo.Context) error {
return ctx.NoContent(http.StatusBadRequest) return ctx.NoContent(http.StatusBadRequest)
} }
ans, err := server.Dal.InsertTransaction(transaction2entity(*t)) transaction, err := server.Dal.InsertTransaction(transaction2entity(*t))
if err != nil { if err != nil {
log.Printf("%v", err) log.Printf("%v", err)
return ctx.NoContent(http.StatusInternalServerError) return ctx.NoContent(http.StatusInternalServerError)
} }
return ctx.JSON(http.StatusCreated, entity2transaction(ans)) return ctx.JSON(http.StatusCreated, entity2transaction(transaction))
}
func (server *ServerImpl) UpdateTransaction(ctx echo.Context) error {
t := new(Transaction)
if err := ctx.Bind(t); err != nil {
log.Printf("%v", err)
return ctx.NoContent(http.StatusBadRequest)
}
transaction := transaction2entity(*t)
exists, err := server.Dal.TransactionExists(transaction.Id)
if err != nil {
log.Printf("%v", err)
return ctx.NoContent(http.StatusInternalServerError)
}
if !exists {
transaction, err := server.Dal.InsertTransaction(transaction)
if err != nil {
log.Printf("%v", err)
return ctx.NoContent(http.StatusInternalServerError)
}
return ctx.JSON(http.StatusCreated, entity2transaction(transaction))
} else {
transaction, err := server.Dal.UpdateTransaction(transaction)
if err != nil {
log.Printf("%v", err)
return ctx.NoContent(http.StatusInternalServerError)
}
return ctx.JSON(http.StatusOK, entity2transaction(transaction))
}
} }

View File

@ -286,3 +286,63 @@ func TestServerImpl_CreateTransaction(t *testing.T) {
}) })
} }
} }
func TestServerImpl_UpdateTransaction(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mock_dal := mock.NewMockDAL(ctrl)
date, _ := time.Parse(time.DateOnly, "1974-04-25")
type fields struct {
Dal dal.DAL
}
type args struct {
request string
}
type want struct {
entity entity.Transaction
response string
}
tests := []struct {
name string
fields fields
args args
want want
wantErr bool
}{
{
"201",
fields{mock_dal},
args{`{"date": "1974-04-25", "description": "freedom", "value": 9000}`},
want{
entity.Transaction{Id: 1, Date: date, Description: "freedom", Value: decimal.New(9000, 0)},
`{"date":"1974-04-25","description":"freedom","id":1,"value":9000}`,
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &ServerImpl{Dal: tt.fields.Dal}
req := httptest.NewRequest(http.MethodPost, "/transactions", strings.NewReader(tt.args.request))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
e := echo.New()
ctx := e.NewContext(req, rec)
inserted := tt.want.entity
inserted.Id = entity.InvalidId
mock_dal.EXPECT().InsertTransaction(gomock.AssignableToTypeOf(reflect.TypeOf(tt.want.entity))).Return(tt.want.entity, nil).Times(1)
if err := s.UpdateTransaction(ctx); (err != nil) != tt.wantErr {
t.Errorf("ServerImpl.GetTransactionById() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(strings.TrimSpace(rec.Body.String()), tt.want.response) {
t.Errorf("DalImpl.InsertTransaction() = %v, want %v", rec.Body.String(), tt.want.response)
}
})
}
}

View File

@ -59,9 +59,21 @@ type GetTransactionsParams struct {
Sort *string `form:"sort,omitempty" json:"sort,omitempty"` Sort *string `form:"sort,omitempty" json:"sort,omitempty"`
} }
// UpdateTransactionJSONBody defines parameters for UpdateTransaction.
type UpdateTransactionJSONBody struct {
Category *string `json:"category,omitempty"`
Date openapi_types.Date `json:"date"`
Description string `json:"description"`
Id int64 `json:"id"`
Value float32 `json:"value"`
}
// CreateTransactionJSONRequestBody defines body for CreateTransaction for application/json ContentType. // CreateTransactionJSONRequestBody defines body for CreateTransaction for application/json ContentType.
type CreateTransactionJSONRequestBody = Transaction type CreateTransactionJSONRequestBody = Transaction
// UpdateTransactionJSONRequestBody defines body for UpdateTransaction for application/json ContentType.
type UpdateTransactionJSONRequestBody UpdateTransactionJSONBody
// ServerInterface represents all server handlers. // ServerInterface represents all server handlers.
type ServerInterface interface { type ServerInterface interface {
// Find bank by ID // Find bank by ID
@ -79,6 +91,9 @@ type ServerInterface interface {
// Create a new transaction // Create a new transaction
// (POST /transactions) // (POST /transactions)
CreateTransaction(ctx echo.Context) error CreateTransaction(ctx echo.Context) error
// Update an existing transaction
// (PUT /transactions)
UpdateTransaction(ctx echo.Context) error
} }
// ServerInterfaceWrapper converts echo contexts to parameters. // ServerInterfaceWrapper converts echo contexts to parameters.
@ -182,6 +197,15 @@ func (w *ServerInterfaceWrapper) CreateTransaction(ctx echo.Context) error {
return err return err
} }
// UpdateTransaction converts echo context to params.
func (w *ServerInterfaceWrapper) UpdateTransaction(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.UpdateTransaction(ctx)
return err
}
// This is a simple interface which specifies echo.Route addition functions which // This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using // are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration // either of them for path registration
@ -215,28 +239,30 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.GET(baseURL+"/transaction/:transactionId", wrapper.GetTransactionById) router.GET(baseURL+"/transaction/:transactionId", wrapper.GetTransactionById)
router.GET(baseURL+"/transactions", wrapper.GetTransactions) router.GET(baseURL+"/transactions", wrapper.GetTransactions)
router.POST(baseURL+"/transactions", wrapper.CreateTransaction) router.POST(baseURL+"/transactions", wrapper.CreateTransaction)
router.PUT(baseURL+"/transactions", wrapper.UpdateTransaction)
} }
// Base64 encoded, gzipped, json marshaled Swagger object // Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{ var swaggerSpec = []string{
"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",
"jkMmmIZdTHto9N8AAAD//+YRCdlGDQAA", "FkMmmIFdH/aIepgB/VMjvxvoQusPVZTJ1392H8Z/pR6OD7NNOXMkhFiHZP7EY70fYdOWyoSZJWakwr8B",
"AAD//5ap8eBoDgAA",
} }
// GetSwagger returns the content of the embedded swagger specification file // GetSwagger returns the content of the embedded swagger specification file

View File

@ -6,6 +6,8 @@ type DAL interface {
Transaction(transactionId int64) (*entity.Transaction, error) Transaction(transactionId int64) (*entity.Transaction, error)
Transactions() (entity.Transactions, error) Transactions() (entity.Transactions, error)
InsertTransaction(entity.Transaction) (entity.Transaction, error) InsertTransaction(entity.Transaction) (entity.Transaction, error)
UpdateTransaction(entity.Transaction) (entity.Transaction, error)
TransactionExists(uint64) (bool, error)
Bank(bankId string) (*entity.Bank, error) Bank(bankId string) (*entity.Bank, error)
Banks() (entity.Banks, error) Banks() (entity.Banks, error)
} }