diff --git a/.vscode/tasks.json b/.vscode/tasks.json index dbad9cd..8bfd2f8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -24,21 +24,63 @@ "type": "go", "label": "go: test workspace", "command": "test", - "options": { - "env": { - "CGO_ENABLED": "0" - }, - "cwd": "${workspaceFolder}/bin", + "cwd": "${workspaceFolder}" }, "args": [ - "../..." + "-v", + "-race", + "-coverprofile=coverage.out", + "-covermode=atomic", + "./..." ], "problemMatcher": [ "$go" ], - "group": "build", - + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + } }, + { + "type": "shell", + "label": "go: vet workspace", + "command": "go vet ./...", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$go" + ], + "group": "test" + }, + { + "type": "shell", + "label": "go: lint workspace", + "command": "golangci-lint run --timeout=5m", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [], + "group": "test" + }, + { + "type": "shell", + "label": "go: full test suite", + "dependsOrder": "sequence", + "dependsOn": [ + "go: vet workspace", + "go: test workspace" + ], + "problemMatcher": [], + "group": { + "kind": "test", + "isDefault": false + } + } ] } \ No newline at end of file diff --git a/pkg/common/validation.go b/pkg/common/validation.go index dbf777b..e70d589 100644 --- a/pkg/common/validation.go +++ b/pkg/common/validation.go @@ -183,7 +183,8 @@ func (v *ColumnValidator) ValidateRequestOptions(options RequestOptions) error { } // Validate Preload columns (if specified) - for _, preload := range options.Preload { + for idx := range options.Preload { + preload := options.Preload[idx] // Note: We don't validate the relation name itself, as it's a relationship // Only validate columns if specified for the preload if err := v.ValidateColumns(preload.Columns); err != nil { @@ -239,7 +240,8 @@ func (v *ColumnValidator) FilterRequestOptions(options RequestOptions) RequestOp // Filter Preload columns validPreloads := make([]PreloadOption, 0, len(options.Preload)) - for _, preload := range options.Preload { + for idx := range options.Preload { + preload := options.Preload[idx] filteredPreload := preload filteredPreload.Columns = v.FilterValidColumns(preload.Columns) filteredPreload.OmitColumns = v.FilterValidColumns(preload.OmitColumns) diff --git a/pkg/reflection/model_utils.go b/pkg/reflection/model_utils.go index 6fd8d1c..0ca6a94 100644 --- a/pkg/reflection/model_utils.go +++ b/pkg/reflection/model_utils.go @@ -18,7 +18,7 @@ func GetPrimaryKeyName(model any) string { if reflect.TypeOf(model) == nil { return "" } - //If we are given a string model name, look up the model + // If we are given a string model name, look up the model if reflect.TypeOf(model).Kind() == reflect.String { name := model.(string) m, err := modelregistry.GetModelByName(name) diff --git a/pkg/resolvespec/handler.go b/pkg/resolvespec/handler.go index 2a7547c..23dc977 100644 --- a/pkg/resolvespec/handler.go +++ b/pkg/resolvespec/handler.go @@ -699,6 +699,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id schema := GetSchema(ctx) entity := GetEntity(ctx) tableName := GetTableName(ctx) + model := GetModel(ctx) logger.Info("Deleting records from %s.%s", schema, entity) @@ -711,7 +712,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id err := h.db.RunInTransaction(ctx, func(tx common.Database) error { for _, itemID := range v { - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) if _, err := query.Exec(ctx); err != nil { return fmt.Errorf("failed to delete record %s: %w", itemID, err) } @@ -750,7 +751,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id continue // Skip items without ID } - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) result, err := query.Exec(ctx) if err != nil { return fmt.Errorf("failed to delete record %v: %w", itemID, err) @@ -775,7 +776,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id err := h.db.RunInTransaction(ctx, func(tx common.Database) error { for _, item := range v { if itemID, ok := item["id"]; ok && itemID != nil { - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) result, err := query.Exec(ctx) if err != nil { return fmt.Errorf("failed to delete record %v: %w", itemID, err) @@ -809,7 +810,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id return } - query := h.db.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), id) + query := h.db.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), id) result, err := query.Exec(ctx) if err != nil { @@ -1118,7 +1119,8 @@ func (h *Handler) applyPreloads(model interface{}, query common.SelectQuery, pre return query } - for _, preload := range preloads { + for idx := range preloads { + preload := preloads[idx] logger.Debug("Processing preload for relation: %s", preload.Relation) relInfo := h.getRelationshipInfo(modelType, preload.Relation) if relInfo == nil { diff --git a/pkg/restheadspec/handler.go b/pkg/restheadspec/handler.go index 3bca219..1d4dd35 100644 --- a/pkg/restheadspec/handler.go +++ b/pkg/restheadspec/handler.go @@ -260,7 +260,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st query = query.ColumnExpr("(?) AS "+colName, colExpr) for colIndex := range options.Columns { if options.Columns[colIndex] == colName { - //Remove the computed column from the selected columns to avoid duplication + // Remove the computed column from the selected columns to avoid duplication options.Columns = append(options.Columns[:colIndex], options.Columns[colIndex+1:]...) break } @@ -274,7 +274,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st query = query.ColumnExpr("(?) AS "+cu.Name, cu.Expression) for colIndex := range options.Columns { if options.Columns[colIndex] == cu.Name { - //Remove the computed column from the selected columns to avoid duplication + // Remove the computed column from the selected columns to avoid duplication options.Columns = append(options.Columns[:colIndex], options.Columns[colIndex+1:]...) break } @@ -305,13 +305,13 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st } // Note: Expand would require JOIN implementation // For now, we'll use Preload as a fallback - //query = query.Preload(expand.Relation) + // query = query.Preload(expand.Relation) if options.Preload == nil { options.Preload = make([]common.PreloadOption, 0) } skip := false - for _, existing := range options.Preload { - if existing.Relation == expand.Relation { + for idx := range options.Preload { + if options.Preload[idx].Relation == expand.Relation { skip = true continue } @@ -327,7 +327,8 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st } // Apply preloading - for _, preload := range options.Preload { + for idx := range options.Preload { + preload := options.Preload[idx] logger.Debug("Applying preload: %s", preload.Relation) query = query.PreloadRelation(preload.Relation, func(sq common.SelectQuery) common.SelectQuery { if len(preload.OmitColumns) > 0 { @@ -972,7 +973,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id continue } - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) result, err := query.Exec(ctx) if err != nil { @@ -1039,7 +1040,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id continue } - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) result, err := query.Exec(ctx) if err != nil { return fmt.Errorf("failed to delete record %v: %w", itemID, err) @@ -1090,7 +1091,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id continue } - query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), itemID) + query := tx.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), itemID) result, err := query.Exec(ctx) if err != nil { return fmt.Errorf("failed to delete record %v: %w", itemID, err) @@ -1150,7 +1151,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id return } - query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(tableName))), id) + query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(reflection.GetPrimaryKeyName(model))), id) // Execute BeforeScan hooks - pass query chain so hooks can modify it hookCtx.Query = query