175 lines
4.1 KiB
Go
175 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/restxlsx/restxlsx/internal/excel"
|
|
"github.com/restxlsx/restxlsx/internal/logger"
|
|
)
|
|
|
|
type RestAPI struct {
|
|
engine *excel.Engine
|
|
log *logger.Logger
|
|
}
|
|
|
|
func NewRestAPI(engine *excel.Engine, log *logger.Logger) *RestAPI {
|
|
return &RestAPI{engine: engine, log: log}
|
|
}
|
|
|
|
func (h *RestAPI) ListTables(w http.ResponseWriter, r *http.Request) {
|
|
h.engine.Lock()
|
|
tables := h.engine.ListTables()
|
|
h.engine.Unlock()
|
|
writeJSON(w, 200, map[string][]string{"tables": tables})
|
|
}
|
|
|
|
func (h *RestAPI) ListRecords(w http.ResponseWriter, r *http.Request) {
|
|
table := chi.URLParam(r, "table")
|
|
h.engine.Lock()
|
|
t := h.engine.GetTable(table)
|
|
if t == nil {
|
|
h.engine.Unlock()
|
|
writeJSON(w, 404, map[string]string{"error": "table not found"})
|
|
return
|
|
}
|
|
rows := t.Rows
|
|
h.engine.Unlock()
|
|
writeJSON(w, 200, rows)
|
|
}
|
|
|
|
func (h *RestAPI) GetRecord(w http.ResponseWriter, r *http.Request) {
|
|
table := chi.URLParam(r, "table")
|
|
id := chi.URLParam(r, "id")
|
|
h.engine.Lock()
|
|
t := h.engine.GetTable(table)
|
|
if t == nil {
|
|
h.engine.Unlock()
|
|
writeJSON(w, 404, map[string]string{"error": "table not found"})
|
|
return
|
|
}
|
|
idCol := h.engine.IDColumn(table)
|
|
for _, row := range t.Rows {
|
|
if fmt.Sprintf("%v", row[idCol]) == id {
|
|
h.engine.Unlock()
|
|
writeJSON(w, 200, row)
|
|
return
|
|
}
|
|
}
|
|
h.engine.Unlock()
|
|
writeJSON(w, 404, map[string]string{"error": "record not found"})
|
|
}
|
|
|
|
func (h *RestAPI) CreateRecord(w http.ResponseWriter, r *http.Request) {
|
|
table := chi.URLParam(r, "table")
|
|
|
|
var rec map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&rec); err != nil {
|
|
writeJSON(w, 400, map[string]string{"error": "invalid JSON: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
h.engine.Lock()
|
|
defer h.engine.Unlock()
|
|
t := h.engine.GetTable(table)
|
|
if t == nil {
|
|
writeJSON(w, 404, map[string]string{"error": "table not found"})
|
|
return
|
|
}
|
|
|
|
idCol := h.engine.IDColumn(table)
|
|
if idCol != "" {
|
|
if _, ok := rec[idCol]; !ok {
|
|
rec[idCol] = len(t.Rows) + 1
|
|
}
|
|
}
|
|
|
|
t.Rows = append(t.Rows, rec)
|
|
if err := h.engine.Flush(); err != nil {
|
|
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 201, rec)
|
|
}
|
|
|
|
func (h *RestAPI) UpdateRecord(w http.ResponseWriter, r *http.Request) {
|
|
table := chi.URLParam(r, "table")
|
|
id := chi.URLParam(r, "id")
|
|
|
|
var rec map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&rec); err != nil {
|
|
writeJSON(w, 400, map[string]string{"error": "invalid JSON: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
h.engine.Lock()
|
|
defer h.engine.Unlock()
|
|
t := h.engine.GetTable(table)
|
|
if t == nil {
|
|
writeJSON(w, 404, map[string]string{"error": "table not found"})
|
|
return
|
|
}
|
|
|
|
idCol := h.engine.IDColumn(table)
|
|
for i, row := range t.Rows {
|
|
if fmt.Sprintf("%v", row[idCol]) == id {
|
|
for k, v := range rec {
|
|
t.Rows[i][k] = v
|
|
}
|
|
if err := h.engine.Flush(); err != nil {
|
|
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, t.Rows[i])
|
|
return
|
|
}
|
|
}
|
|
writeJSON(w, 404, map[string]string{"error": "record not found"})
|
|
}
|
|
|
|
func (h *RestAPI) DeleteRecord(w http.ResponseWriter, r *http.Request) {
|
|
table := chi.URLParam(r, "table")
|
|
id := chi.URLParam(r, "id")
|
|
h.engine.Lock()
|
|
defer h.engine.Unlock()
|
|
t := h.engine.GetTable(table)
|
|
if t == nil {
|
|
writeJSON(w, 404, map[string]string{"error": "table not found"})
|
|
return
|
|
}
|
|
|
|
idCol := h.engine.IDColumn(table)
|
|
for i, row := range t.Rows {
|
|
if fmt.Sprintf("%v", row[idCol]) == id {
|
|
t.Rows = append(t.Rows[:i], t.Rows[i+1:]...)
|
|
if err := h.engine.Flush(); err != nil {
|
|
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 204, nil)
|
|
return
|
|
}
|
|
}
|
|
writeJSON(w, 404, map[string]string{"error": "record not found"})
|
|
}
|
|
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
status int
|
|
}
|
|
|
|
func (rw *responseWriter) WriteHeader(code int) {
|
|
rw.status = code
|
|
rw.ResponseWriter.WriteHeader(code)
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, status int, data any) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
if data != nil {
|
|
json.NewEncoder(w).Encode(data)
|
|
}
|
|
}
|