package handler import ( "net/http" "go.uber.org/zap" "github.com/dbiz/cdp/data-layer/api/internal/middleware" "github.com/dbiz/cdp/data-layer/api/internal/service" ) type SQLHandler struct { svc *service.SQLService log *zap.Logger } func NewSQLHandler(svc *service.SQLService, log *zap.Logger) *SQLHandler { return &SQLHandler{svc: svc, log: log} } type customSQLRequest struct { SQL string `json:"sql" validate:"required,min=1,max=20000"` } // CustomSQL handles POST /query/sql. func (h *SQLHandler) CustomSQL(w http.ResponseWriter, r *http.Request) { var req customSQLRequest if err := decodeAndValidate(r, &req); err != nil { writeError(w, err) return } ws := middleware.WorkspaceFromCtx(r.Context()) res, err := h.svc.Run(r.Context(), req.SQL) if err != nil { h.log.Warn("custom sql rejected", zap.String("workspace_id", ws), zap.Error(err)) writeError(w, err) return } h.log.Info("custom sql ok", zap.String("workspace_id", ws), zap.Int("rows", res.RowCount), zap.Int64("duration_ms", res.DurationMS)) writeJSON(w, http.StatusOK, res) }