package handler import ( "net/http" "github.com/go-chi/chi/v5" "github.com/google/uuid" "go.uber.org/zap" "github.com/dbiz/cdp/data-layer/api/internal/apperr" "github.com/dbiz/cdp/data-layer/api/internal/middleware" "github.com/dbiz/cdp/data-layer/api/internal/model" "github.com/dbiz/cdp/data-layer/api/internal/repo" ) type SavedQueryHandler struct { repo *repo.SavedQueryRepo log *zap.Logger } func NewSavedQueryHandler(r *repo.SavedQueryRepo, log *zap.Logger) *SavedQueryHandler { return &SavedQueryHandler{repo: r, log: log} } type createSavedQueryRequest struct { Name string `json:"name" validate:"required,min=1,max=200"` Kind string `json:"kind" validate:"required,oneof=events sql funnel retention session"` Spec map[string]any `json:"spec" validate:"required"` } type updateSavedQueryRequest struct { Name string `json:"name" validate:"required,min=1,max=200"` Spec map[string]any `json:"spec" validate:"required"` } func (h *SavedQueryHandler) Create(w http.ResponseWriter, r *http.Request) { var req createSavedQueryRequest if err := decodeAndValidate(r, &req); err != nil { writeError(w, err) return } ws := middleware.WorkspaceFromCtx(r.Context()) q, err := h.repo.Create(r.Context(), model.SavedQuery{ WorkspaceID: ws, Name: req.Name, Kind: req.Kind, Spec: req.Spec, }) if err != nil { writeError(w, err) return } writeJSON(w, http.StatusCreated, q) } func (h *SavedQueryHandler) List(w http.ResponseWriter, r *http.Request) { limit, offset := parsePagination(r, 50, 500) ws := middleware.WorkspaceFromCtx(r.Context()) qs, err := h.repo.List(r.Context(), ws, limit, offset) if err != nil { writeError(w, err) return } writeJSON(w, http.StatusOK, map[string]any{"items": qs, "limit": limit, "offset": offset}) } func (h *SavedQueryHandler) Get(w http.ResponseWriter, r *http.Request) { id, err := parseSavedQueryID(r) if err != nil { writeError(w, err) return } ws := middleware.WorkspaceFromCtx(r.Context()) q, err := h.repo.Get(r.Context(), ws, id) if err != nil { writeError(w, err) return } writeJSON(w, http.StatusOK, q) } func (h *SavedQueryHandler) Update(w http.ResponseWriter, r *http.Request) { id, err := parseSavedQueryID(r) if err != nil { writeError(w, err) return } var req updateSavedQueryRequest if err := decodeAndValidate(r, &req); err != nil { writeError(w, err) return } ws := middleware.WorkspaceFromCtx(r.Context()) q, err := h.repo.Update(r.Context(), ws, id, req.Name, req.Spec) if err != nil { writeError(w, err) return } writeJSON(w, http.StatusOK, q) } func (h *SavedQueryHandler) Delete(w http.ResponseWriter, r *http.Request) { id, err := parseSavedQueryID(r) if err != nil { writeError(w, err) return } ws := middleware.WorkspaceFromCtx(r.Context()) if err := h.repo.Delete(r.Context(), ws, id); err != nil { writeError(w, err) return } w.WriteHeader(http.StatusNoContent) } func parseSavedQueryID(r *http.Request) (string, error) { raw := chi.URLParam(r, "id") if raw == "" { return "", apperr.BadRequest("missing query id", "id", nil) } if _, err := uuid.Parse(raw); err != nil { return "", apperr.BadRequest("query id must be uuid", "id", err) } return raw, nil }