up
This commit is contained in:
140
internal/category/category.go
Normal file
140
internal/category/category.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package category
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // income | expense
|
||||
TaxDeductible bool `json:"tax_deductible"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type Store struct{ db *sql.DB }
|
||||
|
||||
func NewStore(db *sql.DB) *Store { return &Store{db: db} }
|
||||
|
||||
func (s *Store) List(txType string) ([]Category, error) {
|
||||
query := `SELECT id, name, type, tax_deductible, COALESCE(description,'') FROM categories WHERE 1=1`
|
||||
args := []any{}
|
||||
if txType != "" {
|
||||
query += " AND type=?"
|
||||
args = append(args, txType)
|
||||
}
|
||||
query += " ORDER BY type, name"
|
||||
rows, err := s.db.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var cats []Category
|
||||
for rows.Next() {
|
||||
var c Category
|
||||
var td int
|
||||
if err := rows.Scan(&c.ID, &c.Name, &c.Type, &td, &c.Description); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.TaxDeductible = td == 1
|
||||
cats = append(cats, c)
|
||||
}
|
||||
return cats, nil
|
||||
}
|
||||
|
||||
func (s *Store) Create(c *Category) error {
|
||||
c.ID = uuid.NewString()
|
||||
td := 0
|
||||
if c.TaxDeductible {
|
||||
td = 1
|
||||
}
|
||||
_, err := s.db.Exec(
|
||||
`INSERT INTO categories (id, name, type, tax_deductible, description) VALUES (?,?,?,?,?)`,
|
||||
c.ID, c.Name, c.Type, td, c.Description,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) Update(c *Category) error {
|
||||
td := 0
|
||||
if c.TaxDeductible {
|
||||
td = 1
|
||||
}
|
||||
_, err := s.db.Exec(
|
||||
`UPDATE categories SET name=?, type=?, tax_deductible=?, description=? WHERE id=?`,
|
||||
c.Name, c.Type, td, c.Description, c.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) Delete(id string) error {
|
||||
s.db.Exec(`UPDATE transactions SET category_id=NULL WHERE category_id=?`, id)
|
||||
_, err := s.db.Exec(`DELETE FROM categories WHERE id=?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
type Handler struct{ store *Store }
|
||||
|
||||
func NewHandler(store *Store) *Handler { return &Handler{store: store} }
|
||||
|
||||
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
|
||||
cats, err := h.store.List(r.URL.Query().Get("type"))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if cats == nil {
|
||||
cats = []Category{}
|
||||
}
|
||||
respond(w, cats)
|
||||
}
|
||||
|
||||
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
var c Category
|
||||
if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
|
||||
http.Error(w, "invalid body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if c.Name == "" || (c.Type != "income" && c.Type != "expense") {
|
||||
http.Error(w, "nom et type (income/expense) requis", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := h.store.Create(&c); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
respond(w, c)
|
||||
}
|
||||
|
||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
var c Category
|
||||
if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
|
||||
http.Error(w, "invalid body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
c.ID = mux.Vars(r)["id"]
|
||||
if err := h.store.Update(&c); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
respond(w, c)
|
||||
}
|
||||
|
||||
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
if err := h.store.Delete(mux.Vars(r)["id"]); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func respond(w http.ResponseWriter, v any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
Reference in New Issue
Block a user