More fixes for _request

This commit is contained in:
Hein 2025-11-11 11:16:07 +02:00
parent 682716dd31
commit 7b8216b71c
7 changed files with 63 additions and 40 deletions

View File

@ -69,7 +69,7 @@ jobs:
cache: true cache: true
- name: Run golangci-lint - name: Run golangci-lint
uses: golangci/golangci-lint-action@v6 uses: golangci/golangci-lint-action@v9
with: with:
version: latest version: latest
args: --timeout=5m args: --timeout=5m

View File

@ -71,9 +71,9 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
RelationData: make(map[string]interface{}), RelationData: make(map[string]interface{}),
} }
// Check if data has a crud_request field that overrides the operation // Check if data has a _request field that overrides the operation
if requestOp := p.extractCRUDRequest(data); requestOp != "" { if requestOp := p.extractCRUDRequest(data); requestOp != "" {
logger.Debug("Found crud_request override: %s", requestOp) logger.Debug("Found _request override: %s", requestOp)
operation = requestOp operation = requestOp
} }
@ -92,8 +92,8 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
regularData := make(map[string]interface{}) regularData := make(map[string]interface{})
for key, value := range data { for key, value := range data {
// Skip crud_request field in actual data processing // Skip _request field in actual data processing
if key == "crud_request" { if key == "_request" {
continue continue
} }
@ -162,9 +162,9 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
return result, nil return result, nil
} }
// extractCRUDRequest extracts the crud_request field from data if present // extractCRUDRequest extracts the request field from data if present
func (p *NestedCUDProcessor) extractCRUDRequest(data map[string]interface{}) string { func (p *NestedCUDProcessor) extractCRUDRequest(data map[string]interface{}) string {
if request, ok := data["crud_request"]; ok { if request, ok := data["_request"]; ok {
if requestStr, ok := request.(string); ok { if requestStr, ok := request.(string); ok {
return strings.ToLower(strings.TrimSpace(requestStr)) return strings.ToLower(strings.TrimSpace(requestStr))
} }
@ -377,10 +377,10 @@ func (p *NestedCUDProcessor) getTableNameForModel(model interface{}, defaultName
} }
// ShouldUseNestedProcessor determines if we should use nested CUD processing // ShouldUseNestedProcessor determines if we should use nested CUD processing
// It checks if the data contains nested relations or a crud_request field // It checks if the data contains nested relations or a _request field
func ShouldUseNestedProcessor(data map[string]interface{}, model interface{}, relationshipHelper RelationshipInfoProvider) bool { func ShouldUseNestedProcessor(data map[string]interface{}, model interface{}, relationshipHelper RelationshipInfoProvider) bool {
// Check for crud_request field // Check for _request field
if _, hasCRUDRequest := data["crud_request"]; hasCRUDRequest { if _, hasCRUDRequest := data["_request"]; hasCRUDRequest {
return true return true
} }
@ -396,8 +396,8 @@ func ShouldUseNestedProcessor(data map[string]interface{}, model interface{}, re
// Check if data contains any fields that are relations (nested objects or arrays) // Check if data contains any fields that are relations (nested objects or arrays)
for key, value := range data { for key, value := range data {
// Skip crud_request and regular scalar fields // Skip _request and regular scalar fields
if key == "crud_request" { if key == "_request" {
continue continue
} }

View File

@ -294,7 +294,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
logger.Info("Creating records for %s.%s", schema, entity) logger.Info("Creating records for %s.%s", schema, entity)
// Check if data contains nested relations or crud_request field // Check if data contains nested relations or _request field
switch v := data.(type) { switch v := data.(type) {
case map[string]interface{}: case map[string]interface{}:
// Check if we should use nested processing // Check if we should use nested processing
@ -1003,7 +1003,7 @@ func (h *Handler) RegisterModel(schema, name string, model interface{}) error {
} }
// shouldUseNestedProcessor determines if we should use nested CUD processing // shouldUseNestedProcessor determines if we should use nested CUD processing
// It checks if the data contains nested relations or a crud_request field // It checks if the data contains nested relations or a _request field
func (h *Handler) shouldUseNestedProcessor(data map[string]interface{}, model interface{}) bool { func (h *Handler) shouldUseNestedProcessor(data map[string]interface{}, model interface{}) bool {
return common.ShouldUseNestedProcessor(data, model, h) return common.ShouldUseNestedProcessor(data, model, h)
} }

View File

@ -10,15 +10,15 @@ type GormTableSchemaInterface interface {
} }
type GormTableCRUDRequest struct { type GormTableCRUDRequest struct {
CRUDRequest *string `json:"crud_request"` Request *string `json:"_request"`
} }
func (r *GormTableCRUDRequest) SetRequest(request string) { func (r *GormTableCRUDRequest) SetRequest(request string) {
r.CRUDRequest = &request r.Request = &request
} }
func (r GormTableCRUDRequest) GetRequest() string { func (r GormTableCRUDRequest) GetRequest() string {
return *r.CRUDRequest return *r.Request
} }
// New interfaces that replace the legacy ones above // New interfaces that replace the legacy ones above

View File

@ -1624,7 +1624,7 @@ func filterExtendedOptions(validator *common.ColumnValidator, options ExtendedRe
} }
// shouldUseNestedProcessor determines if we should use nested CUD processing // shouldUseNestedProcessor determines if we should use nested CUD processing
// It checks if the data contains nested relations or a crud_request field // It checks if the data contains nested relations or a _request field
func (h *Handler) shouldUseNestedProcessor(data map[string]interface{}, model interface{}) bool { func (h *Handler) shouldUseNestedProcessor(data map[string]interface{}, model interface{}) bool {
return common.ShouldUseNestedProcessor(data, model, h) return common.ShouldUseNestedProcessor(data, model, h)
} }

View File

@ -26,7 +26,7 @@ func TestDepartmentEmployees(t *testing.T) {
}, },
} }
resp := makeRequest(t, "/test/departments", deptPayload) resp := makeRequest(t, "/departments", deptPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Create employees in department // Create employees in department
@ -52,7 +52,7 @@ func TestDepartmentEmployees(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/employees", empPayload) resp = makeRequest(t, "/employees", empPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Read department with employees // Read department with employees
@ -68,7 +68,7 @@ func TestDepartmentEmployees(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/departments/dept1", readPayload) resp = makeRequest(t, "/departments/dept1", readPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{} var result map[string]interface{}
@ -92,7 +92,7 @@ func TestEmployeeHierarchy(t *testing.T) {
}, },
} }
resp := makeRequest(t, "/test/employees", mgrPayload) resp := makeRequest(t, "/employees", mgrPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Update employees to set manager // Update employees to set manager
@ -103,9 +103,9 @@ func TestEmployeeHierarchy(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/employees/emp1", updatePayload) resp = makeRequest(t, "/employees/emp1", updatePayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
resp = makeRequest(t, "/test/employees/emp2", updatePayload) resp = makeRequest(t, "/employees/emp2", updatePayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Read manager with reports // Read manager with reports
@ -121,7 +121,7 @@ func TestEmployeeHierarchy(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/employees/mgr1", readPayload) resp = makeRequest(t, "/employees/mgr1", readPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{} var result map[string]interface{}
@ -147,7 +147,7 @@ func TestProjectStructure(t *testing.T) {
}, },
} }
resp := makeRequest(t, "/test/projects", projectPayload) resp := makeRequest(t, "/projects", projectPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Create project tasks // Create project tasks
@ -177,7 +177,7 @@ func TestProjectStructure(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/project_tasks", taskPayload) resp = makeRequest(t, "/project_tasks", taskPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Create task comments // Create task comments
@ -191,7 +191,7 @@ func TestProjectStructure(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/comments", commentPayload) resp = makeRequest(t, "/comments", commentPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// Read project with all relations // Read project with all relations
@ -223,7 +223,7 @@ func TestProjectStructure(t *testing.T) {
}, },
} }
resp = makeRequest(t, "/test/projects/proj1", readPayload) resp = makeRequest(t, "/projects/proj1", readPayload)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{} var result map[string]interface{}

View File

@ -10,6 +10,8 @@ import (
"os" "os"
"testing" "testing"
"github.com/bitechdev/ResolveSpec/pkg/common/adapters/database"
"github.com/bitechdev/ResolveSpec/pkg/common/adapters/router"
"github.com/bitechdev/ResolveSpec/pkg/logger" "github.com/bitechdev/ResolveSpec/pkg/logger"
"github.com/bitechdev/ResolveSpec/pkg/modelregistry" "github.com/bitechdev/ResolveSpec/pkg/modelregistry"
"github.com/bitechdev/ResolveSpec/pkg/resolvespec" "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
@ -117,23 +119,44 @@ func setupTestDB() (*gorm.DB, error) {
func setupTestRouter(db *gorm.DB) http.Handler { func setupTestRouter(db *gorm.DB) http.Handler {
r := mux.NewRouter() r := mux.NewRouter()
// Create a new registry instance // Create database adapter
dbAdapter := database.NewGormAdapter(db)
// Create registry
registry := modelregistry.NewModelRegistry() registry := modelregistry.NewModelRegistry()
// Register test models with the registry // Register test models without schema prefix for SQLite compatibility
// SQLite doesn't support schema prefixes like "test.employees"
testmodels.RegisterTestModels(registry) testmodels.RegisterTestModels(registry)
// Create handler with GORM adapter and the registry // Create handler with pre-populated registry
handler := resolvespec.NewHandlerWithGORM(db) handler := resolvespec.NewHandler(dbAdapter, registry)
// Register test models with the handler for the "test" schema // Setup routes without schema prefix for SQLite
models := testmodels.GetTestModels() // Routes: GET/POST /{entity}, GET/POST/PUT/PATCH/DELETE /{entity}/{id}
modelNames := []string{"departments", "employees", "projects", "project_tasks", "documents", "comments"} r.HandleFunc("/{entity}", func(w http.ResponseWriter, req *http.Request) {
for i, model := range models { vars := mux.Vars(req)
handler.RegisterModel("test", modelNames[i], model) vars["schema"] = "" // Empty schema for SQLite
} reqAdapter := router.NewHTTPRequest(req)
respAdapter := router.NewHTTPResponseWriter(w)
handler.Handle(respAdapter, reqAdapter, vars)
}).Methods("POST")
resolvespec.SetupMuxRoutes(r, handler) r.HandleFunc("/{entity}/{id}", func(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
vars["schema"] = "" // Empty schema for SQLite
reqAdapter := router.NewHTTPRequest(req)
respAdapter := router.NewHTTPResponseWriter(w)
handler.Handle(respAdapter, reqAdapter, vars)
}).Methods("POST")
r.HandleFunc("/{entity}", func(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
vars["schema"] = "" // Empty schema for SQLite
reqAdapter := router.NewHTTPRequest(req)
respAdapter := router.NewHTTPResponseWriter(w)
handler.HandleGet(respAdapter, reqAdapter, vars)
}).Methods("GET")
return r return r
} }