personal-site/ent/admin/templates/handler.tmpl
2025-04-21 20:42:35 -04:00

262 lines
No EOL
9.4 KiB
Cheetah

{{/* Tell Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "admin/handler" }}
// Code generated by ent, DO NOT EDIT.
{{- $pkg := base $.Config.Package }}
package admin
import (
"fmt"
"net/url"
"strconv"
"entgo.io/ent/dialect/sql"
"github.com/labstack/echo/v4"
"{{ $.Config.Package }}"
{{- range $n := $.Nodes }}
"{{ $.Config.Package }}/{{ $n.Package }}"
{{- end }}
)
const dateTimeFormat = "2006-01-02T15:04:05"
const dateTimeFormatNoSeconds = "2006-01-02T15:04"
type Handler struct {
client *{{ $pkg }}.Client
Config HandlerConfig
}
func NewHandler(client *{{ $pkg }}.Client, cfg HandlerConfig) *Handler {
return &Handler{
client: client,
Config: cfg,
}
}
func (h *Handler) Create(ctx echo.Context, entityType string) error {
switch entityType {
{{- range $n := $.Nodes }}
case "{{ $n.Name }}":
return h.{{ $n.Name }}Create(ctx)
{{- end }}
default:
return fmt.Errorf("unsupported entity type: %s", entityType)
}
}
func (h *Handler) Get(ctx echo.Context, entityType string, id int) (url.Values, error) {
switch entityType {
{{- range $n := $.Nodes }}
case "{{ $n.Name }}":
return h.{{ $n.Name }}Get(ctx, id)
{{- end }}
default:
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
}
}
func (h *Handler) Delete(ctx echo.Context, entityType string, id int) error {
switch entityType {
{{- range $n := $.Nodes }}
case "{{ $n.Name }}":
return h.{{ $n.Name }}Delete(ctx, id)
{{- end }}
default:
return fmt.Errorf("unsupported entity type: %s", entityType)
}
}
func (h *Handler) Update(ctx echo.Context, entityType string, id int) error {
switch entityType {
{{- range $n := $.Nodes }}
case "{{ $n.Name }}":
return h.{{ $n.Name }}Update(ctx, id)
{{- end }}
default:
return fmt.Errorf("unsupported entity type: %s", entityType)
}
}
func (h *Handler) List(ctx echo.Context, entityType string) (*EntityList, error) {
switch entityType {
{{- range $n := $.Nodes }}
case "{{ $n.Name }}":
return h.{{ $n.Name }}List(ctx)
{{- end }}
default:
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
}
}
{{ range $n := $.Nodes }}
func (h *Handler) {{ $n.Name }}Create(ctx echo.Context) error {
var payload {{ $n.Name }}
if err := h.bind(ctx, &payload); err != nil {
return err
}
op := h.client.{{ $n.Name }}.Create()
{{- range $f := $n.Fields }}
{{- if (fieldIsPointer $f) }}
if payload.{{ fieldName $f.Name }} != nil {
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
}
{{- else }}
op.Set{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
{{- end }}
{{- end }}
_, err := op.Save(ctx.Request().Context())
return err
}
func (h *Handler) {{ $n.Name }}Update(ctx echo.Context, id int) error {
entity, err := h.client.{{ $n.Name }}.Get(ctx.Request().Context(), id)
if err != nil {
return err
}
var payload {{ $n.Name }}
if err = h.bind(ctx, &payload); err != nil {
return err
}
op := entity.Update()
{{- range $f := $n.Fields }}
{{- if not $f.Immutable }}
{{- if $f.Sensitive }}
if payload.{{ fieldName $f.Name }} != nil {
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
}
{{- else if $f.Nillable }}
op.SetNillable{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
{{- else if $f.Optional }}
if payload.{{ fieldName $f.Name }} == nil {
op.Clear{{ fieldName $f.Name }}()
} else {
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
}
{{- else if (fieldIsPointer $f) }}
if payload.{{ fieldName $f.Name }} == nil {
var empty {{ $f.Type }}
op.Set{{ fieldName $f.Name }}(empty)
} else {
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
}
{{- else }}
op.Set{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
{{- end }}
{{- end }}
{{- end }}
_, err = op.Save(ctx.Request().Context())
return err
}
func (h *Handler) {{ $n.Name }}Delete(ctx echo.Context, id int) error {
return h.client.{{ $n.Name }}.DeleteOneID(id).
Exec(ctx.Request().Context())
}
func (h *Handler) {{ $n.Name }}List(ctx echo.Context) (*EntityList, error) {
page, offset := h.getPageAndOffset(ctx)
res, err := h.client.{{ $n.Name }}.
Query().
Limit(h.Config.ItemsPerPage+1).
Offset(offset).
Order({{ $n.Package }}.ByID(sql.OrderDesc())).
All(ctx.Request().Context())
if err != nil {
return nil, err
}
list := &EntityList{
Columns: []string{
{{- range $f := $n.Fields }}
{{- if not $f.Sensitive }}
"{{ fieldLabel $f.Name }}",
{{- end }}
{{- end }}
},
Entities: make([]EntityValues, 0, len(res)),
Page: page,
HasNextPage: len(res) > h.Config.ItemsPerPage,
}
for i := 0; i <= len(res)-1; i++ {
list.Entities = append(list.Entities, EntityValues{
ID: res[i].ID,
Values: []string{
{{- range $f := $n.Fields }}
{{- if not $f.Sensitive }}
{{- if eq $f.Type.String "string" }}
res[i].{{ fieldName $f.Name }},
{{- else if eq $f.Type.String "time.Time" }}
res[i].{{ fieldName $f.Name }}.Format(h.Config.TimeFormat),
{{- else }}
fmt.Sprint(res[i].{{ fieldName $f.Name }}),
{{- end }}
{{- end }}
{{- end }}
},
})
}
return list, err
}
func (h *Handler) {{ $n.Name }}Get(ctx echo.Context, id int) (url.Values, error) {
entity, err := h.client.{{ $n.Name }}.Get(ctx.Request().Context(), id)
if err != nil {
return nil, err
}
v := url.Values{}
{{- range $f := $n.Fields }}
{{- if and (not $f.Sensitive) (not $f.Immutable) }}
{{- if eq $f.Type.String "string" }}
v.Set("{{ $f.Name }}", entity.{{ fieldName $f.Name }})
{{- else if eq $f.Type.String "time.Time" }}
v.Set("{{ $f.Name }}", entity.{{ fieldName $f.Name }}.Format(dateTimeFormat))
{{- else }}
v.Set("{{ $f.Name }}", fmt.Sprint(entity.{{ fieldName $f.Name }}))
{{- end }}
{{- end }}
{{- end }}
return v, err
}
{{ end }}
func (h *Handler) getPageAndOffset(ctx echo.Context) (int, int) {
if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil {
if page > 1 {
return page, (page-1) * h.Config.ItemsPerPage
}
}
return 1, 0
}
func (h *Handler) bind(ctx echo.Context, entity any) error {
// Echo requires some pre-processing of form values to avoid problems.
for k, v := range ctx.Request().Form {
// Remove empty field values so Echo's bind does not fail when trying to parse things like
// times, etc.
if len(v) == 1 && len(v[0]) == 0 {
delete(ctx.Request().Form, k)
continue
}
// Echo expects datetime values to be in a certain format but that does not align with the datetime-local
// HTML form element format, so we will attempt to convert it here.
for _, format := range []string{dateTimeFormatNoSeconds, dateTimeFormat} {
if t, err := time.Parse(format, v[0]); err == nil {
ctx.Request().Form[k][0] = t.Format(time.RFC3339)
break
}
}
}
return ctx.Bind(entity)
}
{{ end }}