Implements /transaction/{id} GET method

Issue #14
This commit is contained in:
Luís Murta 2024-05-18 22:49:32 +01:00
parent a52bca5882
commit 8839dea7f5
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
6 changed files with 100 additions and 16 deletions

View File

@ -41,6 +41,18 @@ func (pf *ServerImpl) GetTransactions(ctx echo.Context, params GetTransactionsPa
return ctx.JSON(http.StatusOK, convertTransactions(transactions))
}
func (*ServerImpl) GetTransactionById(ctx echo.Context, transactionId int64) error {
return echo.NewHTTPError(http.StatusNotImplemented)
func (pf *ServerImpl) GetTransactionById(ctx echo.Context, transactionId int64) error {
log.Printf("GetTransactionById(%d)", transactionId)
transaction, err := pf.Dal.Transaction(transactionId)
if err != nil {
log.Printf("%v", err)
return ctx.NoContent(http.StatusInternalServerError)
}
if transaction == nil {
return ctx.NoContent(http.StatusNotFound)
}
return ctx.JSON(http.StatusOK, convertTransaction(*transaction))
}

View File

@ -127,11 +127,14 @@ func TestServerImpl_GetTransactions(t *testing.T) {
}
func TestServerImpl_GetTransactionById(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mock_dal := mock.NewMockDAL(ctrl)
type fields struct {
Dal dal.DAL
}
type args struct {
ctx echo.Context
transactionId int64
}
tests := []struct {
@ -139,15 +142,36 @@ func TestServerImpl_GetTransactionById(t *testing.T) {
fields fields
args args
wantErr bool
mocks *entity.Transaction
}{
// TODO: Add test cases.
{
"200",
fields{mock_dal},
args{1},
false,
&entity.Transaction{Id: 1, Date: time.Now(), Description: "desc#1", Value: decimal.New(0, 0)},
},
{
"404",
fields{mock_dal},
args{2},
false,
nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &ServerImpl{
Dal: tt.fields.Dal,
}
if err := s.GetTransactionById(tt.args.ctx, tt.args.transactionId); (err != nil) != tt.wantErr {
req := httptest.NewRequest(http.MethodGet, "/transaction", nil)
rec := httptest.NewRecorder()
ctx := echo.New().NewContext(req, rec)
mock_dal.EXPECT().Transaction(tt.args.transactionId).Return(tt.mocks, nil).Times(1)
if err := s.GetTransactionById(ctx, tt.args.transactionId); (err != nil) != tt.wantErr {
t.Errorf("ServerImpl.GetTransactionById() error = %v, wantErr %v", err, tt.wantErr)
}
})

View File

@ -3,7 +3,7 @@ package dal
import "git.rosemyrtle.work/personal-finance/server/internal/entity"
type DAL interface {
Transaction() (entity.Transaction, error)
Transaction(transactionId int64) (*entity.Transaction, error)
Transactions() (entity.Transactions, error)
Bank() (entity.Bank, error)
Banks() (entity.Banks, error)

View File

@ -12,8 +12,24 @@ type DalImpl struct {
Db *sql.DB
}
func (*DalImpl) Transaction() (entity.Transaction, error) {
return entity.Transaction{}, errors.New("not implemented")
func (dal *DalImpl) Transaction(transactionId int64) (*entity.Transaction, error) {
log.Printf("DAL::Transaction(%d)", transactionId)
if dal.Db == nil {
log.Panic("database not available")
}
rows, err := dal.Db.Query("SELECT t.id, t.date, t.description, t.amount FROM pfbudget.transactions t WHERE t.id = $1", transactionId)
if err != nil {
return nil, err
}
transactions := convert[entity.Transaction](rows)
if len(transactions) == 0 {
return nil, nil
}
return &transactions[0], nil
}
func (dal *DalImpl) Transactions() (entity.Transactions, error) {

View File

@ -13,23 +13,55 @@ import (
)
func TestDalImpl_Transaction(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
date := time.Now()
type fields struct {
Db *sql.DB
}
type args struct {
transactionId int64
rows [][]driver.Value
}
tests := []struct {
name string
fields fields
want entity.Transaction
args args
want *entity.Transaction
wantErr bool
}{
// TODO: Add test cases.
{"notfound", fields{db}, args{2, nil}, nil, false},
{
"found",
fields{db},
args{
1,
[][]driver.Value{
{1, date, "income", 1000},
}},
&entity.Transaction{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000)},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &DalImpl{
Db: tt.fields.Db,
}
got, err := d.Transaction()
mock.
ExpectQuery("^SELECT .* FROM .*transactions t WHERE t.id = \\$1$").
WithArgs(tt.args.transactionId).
WillReturnRows(
mock.
NewRows([]string{"id", "date", "description", "amount"}).
AddRows(tt.args.rows...),
)
got, err := d.Transaction(tt.args.transactionId)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.Transaction() error = %v, wantErr %v", err, tt.wantErr)
return

View File

@ -70,18 +70,18 @@ func (mr *MockDALMockRecorder) Banks() *gomock.Call {
}
// Transaction mocks base method.
func (m *MockDAL) Transaction() (entity.Transaction, error) {
func (m *MockDAL) Transaction(arg0 int64) (*entity.Transaction, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Transaction")
ret0, _ := ret[0].(entity.Transaction)
ret := m.ctrl.Call(m, "Transaction", arg0)
ret0, _ := ret[0].(*entity.Transaction)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Transaction indicates an expected call of Transaction.
func (mr *MockDALMockRecorder) Transaction() *gomock.Call {
func (mr *MockDALMockRecorder) Transaction(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockDAL)(nil).Transaction))
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transaction", reflect.TypeOf((*MockDAL)(nil).Transaction), arg0)
}
// Transactions mocks base method.