Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions cmd/gosqlx/internal/output/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strings"

goerrors "github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

Expand Down Expand Up @@ -37,6 +38,7 @@ type JSONValidationResults struct {
type JSONValidationError struct {
File string `json:"file"`
Message string `json:"message"`
Code string `json:"code,omitempty"`
Type string `json:"type"` // "tokenization", "parsing", "syntax", "io"
}

Expand Down Expand Up @@ -97,6 +99,7 @@ type JSONPosition struct {
// JSONParseError represents a parsing error
type JSONParseError struct {
Message string `json:"message"`
Code string `json:"code,omitempty"`
Type string `json:"type"` // "tokenization", "parsing", "io"
Position *JSONPosition `json:"position,omitempty"`
}
Expand Down Expand Up @@ -130,10 +133,12 @@ func FormatValidationJSON(result *ValidationResult, inputFiles []string, include
// Add errors
for _, fileResult := range result.Files {
if fileResult.Error != nil {
errCode := extractErrorCode(fileResult.Error)
output.Errors = append(output.Errors, JSONValidationError{
File: fileResult.Path,
Message: fileResult.Error.Error(),
Type: categorizeError(fileResult.Error.Error()),
Code: errCode,
Type: categorizeByCode(errCode, fileResult.Error.Error()),
})
}
}
Expand Down Expand Up @@ -219,6 +224,7 @@ func FormatParseJSON(astObj *ast.AST, inputSource string, showTokens bool, token

// FormatParseErrorJSON creates a JSON error output for parse failures
func FormatParseErrorJSON(err error, inputSource string) ([]byte, error) {
errCode := extractErrorCode(err)
output := &JSONParseOutput{
Command: "parse",
Input: JSONInputInfo{
Expand All @@ -229,7 +235,8 @@ func FormatParseErrorJSON(err error, inputSource string) ([]byte, error) {
Status: "error",
Error: &JSONParseError{
Message: err.Error(),
Type: categorizeError(err.Error()),
Code: errCode,
Type: categorizeByCode(errCode, err.Error()),
},
}

Expand Down Expand Up @@ -267,6 +274,34 @@ func determineStatus(result *ValidationResult) string {
return "no_files"
}

// extractErrorCode extracts the error code from an error
func extractErrorCode(err error) string {
if err == nil {
return ""
}
if code, ok := goerrors.ExtractErrorCode(err); ok {
return string(code)
}
return ""
}

// categorizeByCode categorizes errors by error code if available
func categorizeByCode(code, errMsg string) string {
if code != "" {
switch {
case strings.HasPrefix(code, "E1"):
return "tokenization"
case strings.HasPrefix(code, "E2"):
return "parsing"
case strings.HasPrefix(code, "E3"):
return "semantic"
case strings.HasPrefix(code, "E4"):
return "unsupported"
}
}
return categorizeError(errMsg)
}

// categorizeError categorizes error messages by type
func categorizeError(errorMsg string) string {
errorLower := errorMsg
Expand Down
30 changes: 30 additions & 0 deletions docs/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,36 @@ if err := gosqlx.Validate("SELECT * FROM users"); err != nil {

---

#### `ValidateMultiple(queries []string) error`

Validates multiple SQL queries in a batch operation.

```go
queries := []string{
"SELECT * FROM users",
"INSERT INTO logs (msg) VALUES ('test')",
"UPDATE users SET name = 'John' WHERE id = 1",
}
if err := gosqlx.ValidateMultiple(queries); err != nil {
log.Fatal("Validation failed:", err)
}
```

**Parameters:**
- `queries`: A slice of SQL query strings to validate

**Returns:**
- `error`: First validation error encountered, or nil if all queries are valid

**Benefits:**
- Reuses tokenizer and parser objects across queries
- More efficient than calling `Validate()` individually
- Ideal for batch validation scenarios

**Use Case:** Validating multiple SQL queries efficiently

---

### Metadata Extraction

#### `ExtractTables(astNode *ast.AST) []string`
Expand Down
49 changes: 49 additions & 0 deletions docs/CLI_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,55 @@ gosqlx parse -f tree complex_query.sql
gosqlx parse -f json query.sql > ast.json
```

### `gosqlx watch`
Monitor SQL files for changes and validate/format in real-time.

```bash
# Watch current directory for SQL file changes
gosqlx watch

# Watch specific directory with validation
gosqlx watch ./queries --validate

# Watch with formatting on save
gosqlx watch ./queries --format

# Watch with custom pattern
gosqlx watch ./queries --pattern "*.sql"
```

**Options:**
- `--validate`: Run validation on file changes
- `--format`: Auto-format files on save
- `--pattern PATTERN`: File pattern to watch (default: "*.sql")

**Use Case:** Real-time SQL development with automatic validation/formatting

### `gosqlx lint`
Check SQL files for style issues and best practices.

```bash
# Lint SQL files
gosqlx lint query.sql

# Lint with specific rules
gosqlx lint --rules L001,L002,L005 query.sql

# Lint directory recursively
gosqlx lint -r ./queries
```

**Available lint rules:**
- L001: Missing semicolon at end of statement
- L002: Inconsistent keyword casing
- L005: Unused table alias

**Options:**
- `--rules RULES`: Comma-separated list of rule codes to check
- `-r, --recursive`: Recursively process directories

**Use Case:** Enforce SQL coding standards and best practices

## Global Flags

- `-v, --verbose`: Enable verbose output
Expand Down
Loading
Loading