Compare commits
3 Commits
0397253ba7
...
3d9de744e7
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d9de744e7 | |||
| dcadfe73e8 | |||
| 61b1891472 |
@ -1,34 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"log"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func convert[T any](rows *sql.Rows) []T {
|
|
||||||
var ans []T
|
|
||||||
for rows.Next() {
|
|
||||||
var r T
|
|
||||||
s := reflect.ValueOf(&r).Elem()
|
|
||||||
log.Println(s)
|
|
||||||
|
|
||||||
numCols := s.NumField()
|
|
||||||
columns := make([]interface{}, numCols)
|
|
||||||
log.Println(columns)
|
|
||||||
|
|
||||||
for i := 0; i < numCols; i++ {
|
|
||||||
field := s.Field(i)
|
|
||||||
log.Println(field)
|
|
||||||
columns[i] = field.Addr().Interface()
|
|
||||||
}
|
|
||||||
log.Println(columns)
|
|
||||||
|
|
||||||
if err := rows.Scan(columns...); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ans = append(ans, r)
|
|
||||||
}
|
|
||||||
return ans
|
|
||||||
}
|
|
||||||
@ -1,29 +1,31 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
//go:generate go run github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen --config=api.cfg.yaml ../../docs/openapi.yaml
|
//go:generate go run github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen --config=api.cfg.yaml ../../docs/openapi.yaml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
openapi_types "github.com/oapi-codegen/runtime/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerImpl struct {
|
type PersonalFinanceImpl struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ServerImpl) GetBanks(ctx echo.Context) error {
|
func (*PersonalFinanceImpl) GetBanks(ctx echo.Context) error {
|
||||||
return echo.NewHTTPError(http.StatusNotImplemented)
|
return echo.NewHTTPError(http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ServerImpl) GetBanksById(ctx echo.Context, bankId int64) error {
|
func (*PersonalFinanceImpl) GetBanksById(ctx echo.Context, bankId int64) error {
|
||||||
return echo.NewHTTPError(http.StatusNotImplemented)
|
return echo.NewHTTPError(http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pf *ServerImpl) GetTransactions(ctx echo.Context, params GetTransactionsParams) error {
|
func (pf *PersonalFinanceImpl) GetTransactions(ctx echo.Context, params GetTransactionsParams) error {
|
||||||
rows, err := pf.db.Query("SELECT t.category, t.date, t.description, t.id, tc.amount FROM pfbudget.transactions t LEFT JOIN pfbudget.transactions_categorized tc ON t.id = tc.id")
|
rows, err := pf.db.Query("SELECT t.id, t.date, t.description, t.amount, tc.category FROM pfbudget.transactions t LEFT JOIN pfbudget.transactions_categorized tc ON t.id = tc.id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -31,6 +33,39 @@ func (pf *ServerImpl) GetTransactions(ctx echo.Context, params GetTransactionsPa
|
|||||||
return ctx.JSON(http.StatusOK, convert[Transaction](rows))
|
return ctx.JSON(http.StatusOK, convert[Transaction](rows))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ServerImpl) GetTransactionsById(ctx echo.Context, transactionId int64) error {
|
func (*PersonalFinanceImpl) GetTransactionsById(ctx echo.Context, transactionId int64) error {
|
||||||
return echo.NewHTTPError(http.StatusNotImplemented)
|
return echo.NewHTTPError(http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convert[T any](rows *sql.Rows) []T {
|
||||||
|
var ans []T
|
||||||
|
for rows.Next() {
|
||||||
|
var r T
|
||||||
|
s := reflect.ValueOf(&r).Elem()
|
||||||
|
log.Println(s)
|
||||||
|
|
||||||
|
numCols := s.NumField()
|
||||||
|
columns := make([]interface{}, numCols)
|
||||||
|
log.Println(columns)
|
||||||
|
|
||||||
|
for i := 0; i < numCols; i++ {
|
||||||
|
field := s.Field(i)
|
||||||
|
columns[i] = field.Addr().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Scan(columns...); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ans = append(ans, r)
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *openapi_types.Date) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
return errors.New("Null date")
|
||||||
|
}
|
||||||
|
|
||||||
|
// if bv, err := driver.
|
||||||
|
}
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -19,7 +17,7 @@ func TestGetTransactions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
handlers := ServerImpl{db}
|
handlers := PersonalFinanceImpl{db}
|
||||||
RegisterHandlers(e, &handlers)
|
RegisterHandlers(e, &handlers)
|
||||||
|
|
||||||
t.Run("when successful", func(t *testing.T) {
|
t.Run("when successful", func(t *testing.T) {
|
||||||
@ -27,10 +25,10 @@ func TestGetTransactions(t *testing.T) {
|
|||||||
req := httptest.NewRequest(http.MethodGet, "/transactions", nil)
|
req := httptest.NewRequest(http.MethodGet, "/transactions", nil)
|
||||||
|
|
||||||
date := time.Now()
|
date := time.Now()
|
||||||
rows := mock.NewRows([]string{"category", "date", "description", "id", "amount"}).
|
rows := mock.NewRows([]string{"id", "date", "description", "amount", "category"}).
|
||||||
AddRow(nil, date, "#1", 1, 1000).
|
AddRow(1, date, "#1", 1000, nil).
|
||||||
AddRow("expense", date, "#2", 2, -1000)
|
AddRow(2, date, "#2", -1000, "expense")
|
||||||
mock.ExpectQuery("SELECT t.category, t.date, t.description, t.id, tc.amount FROM pfbudget.transactions t LEFT JOIN pfbudget.transactions_categorized tc ON t.id = tc.id").WillReturnRows(rows)
|
mock.ExpectQuery("SELECT t.id, t.date, t.description, t.amount, tc.category FROM pfbudget.transactions t LEFT JOIN pfbudget.transactions_categorized tc ON t.id = tc.id").WillReturnRows(rows)
|
||||||
|
|
||||||
ctx := e.NewContext(req, rec)
|
ctx := e.NewContext(req, rec)
|
||||||
err := handlers.GetTransactions(ctx, GetTransactionsParams{})
|
err := handlers.GetTransactions(ctx, GetTransactionsParams{})
|
||||||
@ -43,23 +41,21 @@ func TestGetTransactions(t *testing.T) {
|
|||||||
|
|
||||||
expected := `[
|
expected := `[
|
||||||
{
|
{
|
||||||
"date":"` + date.Format(time.DateOnly) + `",
|
|
||||||
"description": "#1",
|
|
||||||
"id":1,
|
"id":1,
|
||||||
"value":1000
|
"date":"` + date.Format(time.DateOnly) + `",
|
||||||
|
description": "#1",
|
||||||
|
"amount":1000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"category": "expense",
|
|
||||||
"date":"` + date.Format(time.DateOnly) + `",
|
|
||||||
"description": "#2",
|
|
||||||
"id":2,
|
"id":2,
|
||||||
"value":-1000
|
"date":"` + date.Format(time.DateOnly) + `",
|
||||||
}
|
description": "#2",
|
||||||
|
"amount":-1000,
|
||||||
|
"category": "expense"
|
||||||
|
},
|
||||||
]`
|
]`
|
||||||
expected = strings.Join(strings.Fields(expected), "")
|
if ret := rec.Body.String(); ret != expected {
|
||||||
log.Println(expected)
|
t.Error(ret)
|
||||||
if ret := strings.TrimRight(rec.Body.String(), "\n"); ret != expected {
|
|
||||||
t.Error(ret, expected)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
"github.com/getkin/kin-openapi/openapi3"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
@ -31,25 +29,10 @@ type Bank struct {
|
|||||||
// Banks defines model for Banks.
|
// Banks defines model for Banks.
|
||||||
type Banks = []Bank
|
type Banks = []Bank
|
||||||
|
|
||||||
// Manually added date time that implements the Scanner interface
|
|
||||||
type ScannableDate struct {
|
|
||||||
openapi_types.Date
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ScannableDate) Scan(src any) error {
|
|
||||||
switch s := src.(type) {
|
|
||||||
case time.Time:
|
|
||||||
d.Time = s
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("column is not convertible to date")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transaction defines model for Transaction.
|
// Transaction defines model for Transaction.
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
Category *string `json:"category,omitempty"`
|
Category *string `json:"category,omitempty"`
|
||||||
Date ScannableDate `json:"date"`
|
Date openapi_types.Date `json:"date"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Value float32 `json:"value"`
|
Value float32 `json:"value"`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user