You've already forked reloading-manager
Reviewed-on: Siteworxpro/reloading-manager#8 Co-authored-by: Ron Rise <ron@siteworxpro.com> Co-committed-by: Ron Rise <ron@siteworxpro.com>
512 lines
12 KiB
Go
512 lines
12 KiB
Go
package loads
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"git.siteworxpro.com/reloading-manager/backend/.gen/loading/public/table"
|
|
"git.siteworxpro.com/reloading-manager/backend/database"
|
|
"git.siteworxpro.com/reloading-manager/backend/handlers"
|
|
"git.siteworxpro.com/reloading-manager/backend/handlers/bullets"
|
|
"git.siteworxpro.com/reloading-manager/backend/handlers/primers"
|
|
"git.siteworxpro.com/reloading-manager/backend/models/loads"
|
|
"github.com/go-jet/jet/v2/postgres"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/labstack/echo/v4"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type row struct {
|
|
ID pgtype.UUID
|
|
Col float32
|
|
PowderGr float32
|
|
CartridgeID pgtype.UUID
|
|
CartridgeName string
|
|
CartridgeMeta []byte
|
|
BulletID pgtype.UUID
|
|
BulletName string
|
|
BulletDiameter int32
|
|
BulletWeight int32
|
|
BulletMeta []byte
|
|
BulletManufacturerName string
|
|
BulletManufacturerUrl pgtype.Text
|
|
PrimerID pgtype.UUID
|
|
PrimerName string
|
|
PrimerMeta []byte
|
|
PrimerManufacturerName string
|
|
PrimerManufacturerUrl pgtype.Text
|
|
PowderID pgtype.UUID
|
|
PowderName string
|
|
PowderMeta []byte
|
|
PowderManufacturerName string
|
|
PowderManufacturerUrl pgtype.Text
|
|
}
|
|
|
|
type loadResponseResults struct {
|
|
Id string `json:"id"`
|
|
Cartridge string `json:"cartridge"`
|
|
CartridgeId string `json:"cartridge_id"`
|
|
Col float32 `json:"col"`
|
|
Powder handlers.Powder `json:"powder"`
|
|
PowderGr float32 `json:"powder_gr"`
|
|
Primer primers.PrimerResponse `json:"primer"`
|
|
Bullet bullets.BulletResponse `json:"bullet"`
|
|
}
|
|
|
|
type loadResponse struct {
|
|
Total int `json:"total"`
|
|
Results []loadResponseResults `json:"results"`
|
|
}
|
|
|
|
type ResultChan[T any] struct {
|
|
Result T
|
|
Err error
|
|
}
|
|
|
|
func Post(c echo.Context) error {
|
|
db := c.(*database.CustomContext).Db
|
|
defer func() {
|
|
_ = db.Db.Close(context.Background())
|
|
}()
|
|
|
|
cartridgeID, err := handlers.ParseUuid(c.FormValue("cartridge_id"))
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "cartridge_id is not a valid UUID")
|
|
}
|
|
|
|
powderId, err := handlers.ParseUuid(c.FormValue("powder_id"))
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "powder_id is not a valid UUID")
|
|
}
|
|
|
|
primerId, err := handlers.ParseUuid(c.FormValue("primer_id"))
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "primer_id is not a valid UUID")
|
|
}
|
|
|
|
bulletId, err := handlers.ParseUuid(c.FormValue("bullet_id"))
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "bullet_id is not a valid UUID")
|
|
}
|
|
|
|
file, err := handlers.ReadFile(c, "photo")
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "photo is not valid")
|
|
}
|
|
|
|
meta := c.FormValue("meta")
|
|
if meta == "" {
|
|
meta = "{}"
|
|
}
|
|
|
|
powderGr := c.FormValue("powder_gr")
|
|
if powderGr == "" {
|
|
return handlers.BadRequest(c, "powder_gr is not valid")
|
|
}
|
|
|
|
powderGrFl, err := handlers.ParseFloat32(powderGr)
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "powder_gr is not valid")
|
|
}
|
|
|
|
col := c.FormValue("col")
|
|
if col == "" {
|
|
return handlers.BadRequest(c, "col is not valid")
|
|
}
|
|
colFl, err := handlers.ParseFloat32(col)
|
|
if err != nil {
|
|
return handlers.BadRequest(c, "col is not valid")
|
|
}
|
|
|
|
uid, err := db.Loads.CreateLoad(context.Background(), loads.CreateLoadParams{
|
|
CartridgeID: *cartridgeID,
|
|
Col: colFl,
|
|
PowderID: *powderId,
|
|
PowderGr: powderGrFl,
|
|
PrimerID: *primerId,
|
|
BulletID: *bulletId,
|
|
Photo: file,
|
|
Meta: []byte(meta),
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusCreated, handlers.Response[string]{Payload: uid.String()})
|
|
}
|
|
|
|
func Get(c echo.Context) error {
|
|
id := c.Param("id")
|
|
cResults := make(chan ResultChan[[]loadResponseResults])
|
|
|
|
if id != "" {
|
|
go execResultsQuery(cResults, c)
|
|
results := <-cResults
|
|
|
|
if results.Err != nil {
|
|
return results.Err
|
|
}
|
|
|
|
if len(results.Result) == 0 {
|
|
return handlers.NotFound(c, "load not found")
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, handlers.Response[loadResponseResults]{Status: http.StatusText(http.StatusOK), Payload: results.Result[0]})
|
|
}
|
|
|
|
cTotal := make(chan ResultChan[int64])
|
|
|
|
go func(ch chan ResultChan[int64]) {
|
|
db := database.GetNewDatabase()
|
|
|
|
defer func(Db *pgx.Conn, ctx context.Context) {
|
|
_ = Db.Close(ctx)
|
|
}(db.Db, context.Background())
|
|
|
|
q := getQuery(c, true)
|
|
if q == nil {
|
|
ch <- ResultChan[int64]{Result: 0}
|
|
return
|
|
}
|
|
|
|
sql, params := q.Sql()
|
|
|
|
var total int64
|
|
r := db.Db.QueryRow(context.Background(), sql, params...)
|
|
|
|
err := r.Scan(&total)
|
|
|
|
if err != nil {
|
|
ch <- ResultChan[int64]{Err: err}
|
|
} else {
|
|
ch <- ResultChan[int64]{Result: total}
|
|
}
|
|
}(cTotal)
|
|
go execResultsQuery(cResults, c)
|
|
|
|
total := <-cTotal
|
|
if total.Err != nil {
|
|
return total.Err
|
|
}
|
|
|
|
results := <-cResults
|
|
if results.Err != nil {
|
|
return results.Err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, handlers.Response[loadResponse]{Status: http.StatusText(http.StatusOK), Payload: loadResponse{Total: int(total.Result), Results: results.Result}})
|
|
}
|
|
|
|
func execResultsQuery(ch chan ResultChan[[]loadResponseResults], c echo.Context) {
|
|
db := database.GetNewDatabase()
|
|
|
|
defer func(Db *pgx.Conn, ctx context.Context) {
|
|
_ = Db.Close(ctx)
|
|
}(db.Db, context.Background())
|
|
|
|
q := getQuery(c, false)
|
|
|
|
if q == nil {
|
|
ch <- ResultChan[[]loadResponseResults]{Result: []loadResponseResults{}}
|
|
return
|
|
}
|
|
|
|
fmt.Println(q.DebugSql())
|
|
|
|
sql, params := q.Sql()
|
|
rows, err := db.Db.Query(context.Background(), sql, params...)
|
|
|
|
if err != nil {
|
|
ch <- ResultChan[[]loadResponseResults]{Err: err}
|
|
return
|
|
}
|
|
|
|
results := make([]loadResponseResults, 0)
|
|
for rows.Next() {
|
|
row := row{}
|
|
err = rows.Scan(
|
|
&row.ID,
|
|
&row.Col,
|
|
&row.PowderGr,
|
|
|
|
&row.CartridgeID,
|
|
&row.CartridgeName,
|
|
&row.CartridgeMeta,
|
|
|
|
&row.BulletID,
|
|
&row.BulletName,
|
|
&row.BulletDiameter,
|
|
&row.BulletWeight,
|
|
&row.BulletMeta,
|
|
&row.BulletManufacturerName,
|
|
&row.BulletManufacturerUrl,
|
|
|
|
&row.PrimerID,
|
|
&row.PrimerName,
|
|
&row.PrimerMeta,
|
|
&row.PrimerManufacturerName,
|
|
&row.PrimerManufacturerUrl,
|
|
|
|
&row.PowderID,
|
|
&row.PowderName,
|
|
&row.PowderMeta,
|
|
&row.PowderManufacturerName,
|
|
&row.PowderManufacturerUrl,
|
|
)
|
|
|
|
if err != nil {
|
|
ch <- ResultChan[[]loadResponseResults]{Err: err}
|
|
|
|
return
|
|
}
|
|
|
|
results = append(results, loadResponseResults{
|
|
Id: row.ID.String(),
|
|
Cartridge: row.CartridgeName,
|
|
CartridgeId: row.CartridgeID.String(),
|
|
Col: row.Col,
|
|
Powder: handlers.Powder{
|
|
Id: row.PowderID.String(),
|
|
Name: row.PowderName,
|
|
Meta: string(row.PowderMeta),
|
|
Manufacturer: handlers.Manufacturer{
|
|
Name: row.PowderManufacturerName,
|
|
Url: row.PowderManufacturerUrl.String,
|
|
},
|
|
},
|
|
PowderGr: row.PowderGr,
|
|
Primer: primers.PrimerResponse{
|
|
ID: row.PrimerID.String(),
|
|
Name: row.PrimerName,
|
|
Manufacturer: handlers.Manufacturer{
|
|
Name: row.PrimerManufacturerName,
|
|
Url: row.PrimerManufacturerUrl.String,
|
|
},
|
|
},
|
|
Bullet: bullets.BulletResponse{
|
|
Id: row.BulletID.String(),
|
|
Name: row.BulletName,
|
|
Diameter: row.BulletDiameter,
|
|
Weight: row.BulletWeight,
|
|
Manufacturer: handlers.Manufacturer{
|
|
Name: row.BulletManufacturerName,
|
|
Url: row.BulletManufacturerUrl.String,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
ch <- ResultChan[[]loadResponseResults]{Result: results}
|
|
}
|
|
|
|
func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
|
|
l := table.Loads.AS("l")
|
|
ctg := table.Cartridges.AS("c")
|
|
b := table.Bullets.AS("b")
|
|
bm := table.Manufacturers.AS("b_m")
|
|
p := table.Primers.AS("p")
|
|
pm := table.Manufacturers.AS("p_m")
|
|
pwd := table.Powders.AS("pw")
|
|
pwdm := table.Manufacturers.AS("pw_m")
|
|
|
|
tb := l.
|
|
INNER_JOIN(ctg, l.CartridgeID.EQ(ctg.ID)).
|
|
INNER_JOIN(b, l.BulletID.EQ(b.ID)).
|
|
INNER_JOIN(bm, b.ManufacturerID.EQ(bm.ID)).
|
|
INNER_JOIN(p, l.PrimerID.EQ(p.ID)).
|
|
INNER_JOIN(pm, p.ManufacturerID.EQ(pm.ID)).
|
|
INNER_JOIN(pwd, l.PowderID.EQ(pwd.ID)).
|
|
INNER_JOIN(pwdm, pwd.ManufacturerID.EQ(pwdm.ID))
|
|
|
|
var q postgres.SelectStatement
|
|
if countOnly {
|
|
q = tb.SELECT(postgres.COUNT(l.ID).AS("total"))
|
|
} else {
|
|
q = tb.SELECT(
|
|
// Load
|
|
l.ID.AS("id"),
|
|
l.Col.AS("col"),
|
|
l.PowderGr.AS("powder_gr"),
|
|
|
|
// Cartridge
|
|
ctg.ID.AS("cartridge_id"),
|
|
ctg.Name.AS("cartridge_name"),
|
|
ctg.Meta.AS("cartridge_meta"),
|
|
|
|
// Bullet
|
|
b.ID.AS("bullet_id"),
|
|
b.Name.AS("bullet_name"),
|
|
b.Diameter.AS("bullet_diameter"),
|
|
b.Weight.AS("bullet_weight"),
|
|
b.Meta.AS("bullet_meta"),
|
|
bm.Name.AS("bullet_manufacturer_name"),
|
|
bm.URL.AS("bullet_manufacturer_url"),
|
|
|
|
// Primer
|
|
p.ID.AS("primer_id"),
|
|
p.Name.AS("primer_name"),
|
|
p.Meta.AS("primer_meta"),
|
|
pm.Name.AS("primer_manufacturer_name"),
|
|
pm.URL.AS("primer_manufacturer_url"),
|
|
|
|
// Powder
|
|
pwd.ID.AS("powder_id"),
|
|
pwd.Name.AS("powder_name"),
|
|
pwd.Meta.AS("powder_meta"),
|
|
pwdm.Name.AS("powder_manufacturer_name"),
|
|
pwdm.URL.AS("powder_manufacturer_url"),
|
|
)
|
|
}
|
|
|
|
// where expressions
|
|
expressions := make([]postgres.BoolExpression, 0)
|
|
|
|
if c.Param("id") != "" {
|
|
uuid, err := handlers.ParseUuid(c.Param("id"))
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
q = q.WHERE(l.ID.EQ(postgres.UUID(uuid)))
|
|
|
|
return q
|
|
}
|
|
|
|
if c.QueryParam("cartridge_id") != "" {
|
|
ids := strings.Split(c.QueryParam("cartridge_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, ctg.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("bullet_manufacturer_id") != "" {
|
|
ids := strings.Split(c.QueryParam("bullet_manufacturer_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, bm.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("bullet_id") != "" {
|
|
ids := strings.Split(c.QueryParam("bullet_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, b.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("primer_manufacturer_id") != "" {
|
|
ids := strings.Split(c.QueryParam("primer_manufacturer_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, pm.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("primer_id") != "" {
|
|
ids := strings.Split(c.QueryParam("primer_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, p.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("powder_manufacturer_id") != "" {
|
|
ids := strings.Split(c.QueryParam("powder_manufacturer_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, pwdm.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("powder_id") != "" {
|
|
ids := strings.Split(c.QueryParam("powder_id"), ",")
|
|
if len(ids) > 0 {
|
|
expressions = append(expressions, pwd.ID.IN(getUuidExpr(ids)...))
|
|
}
|
|
}
|
|
|
|
if c.QueryParam("search_cartridge") != "" {
|
|
expressions = append(expressions, ctg.Name.LIKE(postgres.String(c.QueryParam("search_cartridge")+"%")))
|
|
}
|
|
|
|
if c.QueryParam("search_bullet") != "" {
|
|
expressions = append(expressions, b.Name.LIKE(postgres.String(c.QueryParam("search_bullet")+"%")))
|
|
}
|
|
|
|
var where postgres.BoolExpression
|
|
if len(expressions) > 0 {
|
|
for _, expr := range expressions {
|
|
if where == nil {
|
|
where = expr
|
|
} else {
|
|
where = where.AND(expr)
|
|
}
|
|
}
|
|
}
|
|
|
|
if where != nil {
|
|
q = q.WHERE(where)
|
|
}
|
|
|
|
if countOnly {
|
|
return q
|
|
}
|
|
|
|
orderBy := c.QueryParam("sortField")
|
|
var sort postgres.Column
|
|
switch orderBy {
|
|
case "cartridge_name":
|
|
sort = ctg.Name
|
|
case "bullet_name":
|
|
sort = b.Name
|
|
case "bullet_manufacturer_name":
|
|
sort = bm.Name
|
|
case "primer_manufacturer_name":
|
|
sort = pm.Name
|
|
case "primer_name":
|
|
sort = p.Name
|
|
case "powder_manufacturer_name":
|
|
sort = pwdm.Name
|
|
case "powder_name":
|
|
sort = pwd.Name
|
|
case "powder_grs":
|
|
sort = l.PowderGr
|
|
default:
|
|
sort = ctg.Name
|
|
}
|
|
|
|
if c.QueryParam("sortOrder") == "desc" {
|
|
q.ORDER_BY(sort.DESC())
|
|
} else {
|
|
q.ORDER_BY(sort.ASC())
|
|
}
|
|
|
|
limit := c.QueryParam("limit")
|
|
if limit == "" {
|
|
limit = "50"
|
|
}
|
|
|
|
pageInt := handlers.ParseInt64OrDefault(c.QueryParam("page"), 1)
|
|
if pageInt < 1 {
|
|
pageInt = 1
|
|
}
|
|
|
|
offset := (pageInt - 1) * handlers.ParseInt64OrDefault(limit, 50)
|
|
q = q.LIMIT(handlers.ParseInt64OrDefault(limit, 50)).
|
|
OFFSET(offset)
|
|
|
|
return q
|
|
}
|
|
|
|
func getUuidExpr(ids []string) []postgres.Expression {
|
|
expr := make([]postgres.Expression, 0)
|
|
for _, id := range ids {
|
|
uuid, err := handlers.ParseUuid(id)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
expr = append(expr, postgres.UUID(uuid))
|
|
}
|
|
|
|
return expr
|
|
}
|