263 lines
4.9 KiB
Go
263 lines
4.9 KiB
Go
package crud
|
|
|
|
import (
|
|
"math"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"gitnet.fr/deblan/budget/database/manager"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type UpdateCallback func(*gorm.DB, interface{}, interface{}) (interface{}, error)
|
|
type CreateCallback func(*gorm.DB, interface{}) (interface{}, error)
|
|
|
|
type Error struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
type Controller struct {
|
|
Config Configuration
|
|
}
|
|
|
|
func New() *Controller {
|
|
c := Controller{}
|
|
|
|
return &c
|
|
}
|
|
|
|
func (ctrl *Controller) With(config Configuration) *Controller {
|
|
ctrl.Config = config
|
|
return ctrl
|
|
}
|
|
|
|
func (ctrl *Controller) List(c echo.Context) error {
|
|
db := manager.Get().Db
|
|
db = db.Model(ctrl.Config.Model)
|
|
|
|
order := c.QueryParam("order")
|
|
sort := c.QueryParam("sort")
|
|
|
|
if !ctrl.Config.IsValidOrder(order) {
|
|
order = ctrl.Config.GetDefaultOrder()
|
|
sort = ctrl.Config.GetDefaultSort()
|
|
}
|
|
|
|
db.Order(clause.OrderByColumn{
|
|
Column: clause.Column{Name: order},
|
|
Desc: sort == "desc",
|
|
})
|
|
|
|
if ctrl.Config.ListQuery != nil {
|
|
ctrl.Config.ListQuery(db)
|
|
}
|
|
|
|
data := ListData{
|
|
Limit: ctrl.Config.DefaultLimit,
|
|
Order: order,
|
|
Sort: sort,
|
|
}
|
|
|
|
limit, err := strconv.Atoi(c.QueryParam("limit"))
|
|
|
|
if err == nil && ctrl.Config.IsValidLimit(limit) {
|
|
data.Limit = limit
|
|
}
|
|
|
|
page, err := strconv.Atoi(c.QueryParam("page"))
|
|
|
|
if err == nil && page > 0 {
|
|
data.Page = page
|
|
}
|
|
|
|
ctrl.ApplyFilters(c.QueryParams(), db)
|
|
ctrl.Paginate(&data, db)
|
|
|
|
return c.JSON(200, data)
|
|
}
|
|
|
|
func (ctrl *Controller) Show(c echo.Context) error {
|
|
db := manager.Get().Db
|
|
value, err := strconv.Atoi(c.Param("id"))
|
|
|
|
if err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
var count int64
|
|
db.Model(ctrl.Config.Model).Where("id = ?", value).Count(&count)
|
|
|
|
if count == 0 {
|
|
return c.JSON(404, Error{
|
|
Code: 404,
|
|
Message: "Not found",
|
|
})
|
|
}
|
|
|
|
item := ctrl.Config.CreateModel()
|
|
db.Model(ctrl.Config.Model).Where("id = ?", value)
|
|
|
|
if ctrl.Config.ItemQuery != nil {
|
|
ctrl.Config.ItemQuery(db)
|
|
}
|
|
|
|
db.First(&item)
|
|
|
|
return c.JSON(200, item)
|
|
}
|
|
|
|
func (ctrl *Controller) Delete(c echo.Context) error {
|
|
db := manager.Get().Db
|
|
value, err := strconv.Atoi(c.Param("id"))
|
|
|
|
if err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
var count int64
|
|
db.Model(ctrl.Config.Model).Where("id = ?", value).Count(&count)
|
|
|
|
if count == 0 {
|
|
return c.JSON(404, Error{
|
|
Code: 404,
|
|
Message: "Not found",
|
|
})
|
|
}
|
|
|
|
item := ctrl.Config.CreateModel()
|
|
db.Model(ctrl.Config.Model).Where("id = ?", value).Delete(&item)
|
|
|
|
return c.JSON(200, nil)
|
|
}
|
|
|
|
func (ctrl *Controller) Create(c echo.Context, body interface{}, createCallback CreateCallback) error {
|
|
db := manager.Get().Db
|
|
|
|
if err := c.Bind(body); err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: "Bad request",
|
|
})
|
|
}
|
|
|
|
if err := c.Validate(body); err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
result, err := createCallback(db, body)
|
|
|
|
if err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(200, result)
|
|
}
|
|
|
|
func (ctrl *Controller) Update(c echo.Context, body interface{}, updateCallback UpdateCallback) error {
|
|
db := manager.Get().Db
|
|
value, err := strconv.Atoi(c.Param("id"))
|
|
|
|
if err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
var count int64
|
|
db.Model(ctrl.Config.Model).Where("id = ?", value).Count(&count)
|
|
|
|
if count == 0 {
|
|
return c.JSON(404, Error{
|
|
Code: 404,
|
|
Message: "Not found",
|
|
})
|
|
}
|
|
|
|
item := ctrl.Config.CreateModel()
|
|
db = db.Model(ctrl.Config.Model)
|
|
|
|
if ctrl.Config.ItemQuery != nil {
|
|
ctrl.Config.ItemQuery(db)
|
|
}
|
|
|
|
db.First(&item, value)
|
|
|
|
if err := c.Bind(body); err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
if err := c.Validate(body); err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
result, err := updateCallback(db, item, body)
|
|
|
|
if err != nil {
|
|
return c.JSON(400, Error{
|
|
Code: 400,
|
|
Message: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(200, result)
|
|
}
|
|
|
|
func (ctrl *Controller) Paginate(data *ListData, db *gorm.DB) {
|
|
var totalRows int64
|
|
db.Model(ctrl.Config.Model).Count(&totalRows)
|
|
|
|
data.TotalRows = totalRows
|
|
totalPages := int(math.Ceil(float64(totalRows) / float64(data.Limit)))
|
|
data.TotalPages = totalPages
|
|
|
|
if data.Limit > 0 {
|
|
db.Offset(data.GetOffset())
|
|
db.Limit(data.GetLimit())
|
|
}
|
|
|
|
db.Find(&ctrl.Config.Models)
|
|
|
|
data.Rows = ctrl.Config.Models
|
|
}
|
|
|
|
func (ctrl *Controller) ApplyFilters(value url.Values, db *gorm.DB) {
|
|
for name, value := range value {
|
|
elements := strings.Split(name, "__")
|
|
|
|
if len(elements) != 2 {
|
|
continue
|
|
}
|
|
|
|
field := elements[0]
|
|
comparator := elements[1]
|
|
|
|
if !ctrl.Config.IsValidOrder(field) {
|
|
continue
|
|
}
|
|
|
|
manager.DbComparator(db, ctrl.Config.Table, field, comparator, value[0])
|
|
}
|
|
}
|