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
131 lines
3.1 KiB
Go
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))
|
|
}
|