From 7b8216b71ca0e11fb2757ecdcba6e792b0c08818 Mon Sep 17 00:00:00 2001 From: Hein Date: Tue, 11 Nov 2025 11:16:07 +0200 Subject: [PATCH] More fixes for _request --- .github/workflows/test.yml | 2 +- pkg/common/recursive_crud.go | 22 ++++++++--------- pkg/resolvespec/handler.go | 4 ++-- pkg/resolvespec/interfaces.go | 6 ++--- pkg/restheadspec/handler.go | 2 +- tests/integration_test.go | 22 ++++++++--------- tests/test_helpers.go | 45 ++++++++++++++++++++++++++--------- 7 files changed, 63 insertions(+), 40 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c9e1b84..1245423 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -69,7 +69,7 @@ jobs: cache: true - name: Run golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v9 with: version: latest args: --timeout=5m diff --git a/pkg/common/recursive_crud.go b/pkg/common/recursive_crud.go index b8d455d..d085cf1 100644 --- a/pkg/common/recursive_crud.go +++ b/pkg/common/recursive_crud.go @@ -71,9 +71,9 @@ func (p *NestedCUDProcessor) ProcessNestedCUD( 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 != "" { - logger.Debug("Found crud_request override: %s", requestOp) + logger.Debug("Found _request override: %s", requestOp) operation = requestOp } @@ -92,8 +92,8 @@ func (p *NestedCUDProcessor) ProcessNestedCUD( regularData := make(map[string]interface{}) for key, value := range data { - // Skip crud_request field in actual data processing - if key == "crud_request" { + // Skip _request field in actual data processing + if key == "_request" { continue } @@ -162,9 +162,9 @@ func (p *NestedCUDProcessor) ProcessNestedCUD( 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 { - if request, ok := data["crud_request"]; ok { + if request, ok := data["_request"]; ok { if requestStr, ok := request.(string); ok { 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 -// 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 { - // Check for crud_request field - if _, hasCRUDRequest := data["crud_request"]; hasCRUDRequest { + // Check for _request field + if _, hasCRUDRequest := data["_request"]; hasCRUDRequest { 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) for key, value := range data { - // Skip crud_request and regular scalar fields - if key == "crud_request" { + // Skip _request and regular scalar fields + if key == "_request" { continue } diff --git a/pkg/resolvespec/handler.go b/pkg/resolvespec/handler.go index c0ef4b5..8244cda 100644 --- a/pkg/resolvespec/handler.go +++ b/pkg/resolvespec/handler.go @@ -294,7 +294,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat 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) { case map[string]interface{}: // 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 -// 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 { return common.ShouldUseNestedProcessor(data, model, h) } diff --git a/pkg/resolvespec/interfaces.go b/pkg/resolvespec/interfaces.go index 16cf4a4..2ef2379 100644 --- a/pkg/resolvespec/interfaces.go +++ b/pkg/resolvespec/interfaces.go @@ -10,15 +10,15 @@ type GormTableSchemaInterface interface { } type GormTableCRUDRequest struct { - CRUDRequest *string `json:"crud_request"` + Request *string `json:"_request"` } func (r *GormTableCRUDRequest) SetRequest(request string) { - r.CRUDRequest = &request + r.Request = &request } func (r GormTableCRUDRequest) GetRequest() string { - return *r.CRUDRequest + return *r.Request } // New interfaces that replace the legacy ones above diff --git a/pkg/restheadspec/handler.go b/pkg/restheadspec/handler.go index 979027d..a092755 100644 --- a/pkg/restheadspec/handler.go +++ b/pkg/restheadspec/handler.go @@ -1624,7 +1624,7 @@ func filterExtendedOptions(validator *common.ColumnValidator, options ExtendedRe } // 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 { return common.ShouldUseNestedProcessor(data, model, h) } diff --git a/tests/integration_test.go b/tests/integration_test.go index 94f9add..e20f6fb 100644 --- a/tests/integration_test.go +++ b/tests/integration_test.go @@ -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) // 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) // 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) 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) // 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) - resp = makeRequest(t, "/test/employees/emp2", updatePayload) + resp = makeRequest(t, "/employees/emp2", updatePayload) assert.Equal(t, http.StatusOK, resp.StatusCode) // 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) 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) // 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) // 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) // 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) var result map[string]interface{} diff --git a/tests/test_helpers.go b/tests/test_helpers.go index 2b58a99..cf10065 100644 --- a/tests/test_helpers.go +++ b/tests/test_helpers.go @@ -10,6 +10,8 @@ import ( "os" "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/modelregistry" "github.com/bitechdev/ResolveSpec/pkg/resolvespec" @@ -117,23 +119,44 @@ func setupTestDB() (*gorm.DB, error) { func setupTestRouter(db *gorm.DB) http.Handler { r := mux.NewRouter() - // Create a new registry instance + // Create database adapter + dbAdapter := database.NewGormAdapter(db) + + // Create registry 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) - // Create handler with GORM adapter and the registry - handler := resolvespec.NewHandlerWithGORM(db) + // Create handler with pre-populated registry + handler := resolvespec.NewHandler(dbAdapter, registry) - // Register test models with the handler for the "test" schema - models := testmodels.GetTestModels() - modelNames := []string{"departments", "employees", "projects", "project_tasks", "documents", "comments"} - for i, model := range models { - handler.RegisterModel("test", modelNames[i], model) - } + // Setup routes without schema prefix for SQLite + // Routes: GET/POST /{entity}, GET/POST/PUT/PATCH/DELETE /{entity}/{id} + 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.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 }