Luís Murta 19974a5f44
Working /transactions endpoint with DB connection
Adds the database abstraction layer (DAL) with a Transactions method
and a Connection object to encapsulate the DB open connection.
Includes a DAL unit test using the go-sqlmock library.

Connection to a PostgreSQL database using environment variables to
store the secrets.

Overall, with the /transactions endpoint requesting directly to the DB,
this patch finish the tracer bullet project.

Issues #1, #5, #6 and #7
2024-02-13 19:27:26 +00:00

131 lines
3.1 KiB
Go

package main
import (
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
"git.rosemyrtle.work/personal-finance/server/internal/dal"
"git.rosemyrtle.work/personal-finance/server/internal/entities"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/shopspring/decimal"
)
// Transaction struct represents a transaction
type Transaction struct {
Id int64 `json:"id"`
Date string `json:"date"`
Description string `json:"description"`
Value float64 `json:"value"`
Category string `json:"category,omitempty"`
}
// Bank struct represents a bank
type Bank struct {
ID string `json:"id"`
Name string `json:"name"`
NordigenID string `json:"nordigenId,omitempty"`
}
type Env struct {
db *dal.Connection
}
func (e *Env) retrieveTransactions(c *gin.Context) {
// Handle the logic for retrieving transactions here
// limit := c.Query("limit")
// offset := c.Query("offset")
// bank := c.Query("bank")
// sort := c.Query("sort")
transactions := e.db.Transactions()
var ret []Transaction
for _, t := range transactions {
year, month, day := t.Date.Date()
var b strings.Builder
fmt.Fprintf(&b, "%d-%d-%d", year, month, day)
ret = append(ret, Transaction{t.Id, b.String(), t.Description, t.Value.InexactFloat64(), t.Category})
}
c.JSON(http.StatusOK, ret)
}
func (e *Env) retrieveTransactionByID(c *gin.Context) {
// Handle the logic for retrieving a transaction by ID here
// transactionID := c.Param("transactionId")
// Placeholder response
transaction := entities.Transaction{
Id: 1,
Date: time.Date(2024, 01, 24, 0, 0, 0, 0, time.UTC),
Description: "Groceries",
Value: decimal.NewFromFloat(-50.0),
Category: "Food",
}
c.JSON(http.StatusOK, transaction)
}
func (e *Env) retrieveBanks(c *gin.Context) {
// Handle the logic for retrieving banks here
// Placeholder response
banks := []Bank{
{ID: "1", Name: "Bank A", NordigenID: "uuid1"},
{ID: "2", Name: "Bank B", NordigenID: "uuid2"},
}
c.JSON(http.StatusOK, banks)
}
func (e *Env) retrieveBankByID(c *gin.Context) {
// Handle the logic for retrieving a bank by ID here
bankID := c.Param("bankId")
// Placeholder response
bank := Bank{ID: bankID, Name: "Bank A", NordigenID: "uuid1"}
c.JSON(http.StatusOK, bank)
}
func main() {
if err := godotenv.Load(); err != nil {
log.Fatal("Error loading .env file")
return
}
user := os.Getenv("PG_USER")
pass := os.Getenv("PG_PASSWORD")
location := os.Getenv("PG_URL")
database := os.Getenv("PG_DB")
credentials := entities.Credentials{Database: "postgres://" + user + ":" + pass + "@" + location + "/" + database}
db, err := dal.Open(&credentials)
if err != nil {
log.Fatal(err)
return
}
defer db.Close()
router := gin.Default()
env := Env{db: db}
// Routes
router.GET("/transactions", env.retrieveTransactions)
router.GET("/transactions/:transactionId", env.retrieveTransactionByID)
router.GET("/banks", env.retrieveBanks)
router.GET("/banks/:bankId", env.retrieveBankByID)
// Start server
port := 8080
fmt.Printf("Server is running on :%d...\n", port)
router.Run(fmt.Sprintf(":%d", port))
}