Help us shape the future of Go! Take the 2026 Go Developer Survey

linter

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

QueryDSL Linter

A validation and parsing library for Yao QueryDSL with precise error location reporting, similar to a code linter.

Overview

This package provides:

  • Parsing - Parse JSON DSL strings into gou.QueryDSL structs
  • Validation - Validate DSL structure with detailed error diagnostics
  • Position Tracking - Report exact line/column positions for errors
  • Error Codes - Programmatic error codes for automated handling

Installation

import "github.com/yaoapp/gou/query/linter"

Usage

Parse and Validate
// Parse returns both the DSL and validation result
dsl, result := linter.Parse(source)

if result.Valid {
    // DSL is ready to use
    fmt.Println("Select fields:", dsl.Select)
} else {
    // Handle errors
    fmt.Println(result.FormatDiagnostics())
}
Validate Only
// Lint returns only the validation result
result := linter.Lint(source)

if result.HasErrors() {
    for _, err := range result.Errors() {
        fmt.Printf("Line %d, Col %d: %s\n", 
            err.Position.Line, 
            err.Position.Column, 
            err.Message)
    }
}
Parse with Panic on Error
// MustParse panics if validation fails - useful for tests
dsl := linter.MustParse(source)

Types

LintResult
type LintResult struct {
    DSL         *gou.QueryDSL // Parsed DSL (nil if failed)
    Diagnostics []Diagnostic  // All diagnostics found
    Valid       bool          // True if no errors
}

// Methods
result.HasErrors() bool           // Check if any errors exist
result.Errors() []Diagnostic      // Get only error-level diagnostics
result.Warnings() []Diagnostic    // Get only warning-level diagnostics
result.FormatDiagnostics() string // Format all diagnostics as string
Diagnostic
type Diagnostic struct {
    Severity Severity // SeverityError, SeverityWarning, SeverityInfo, SeverityHint
    Message  string   // Human-readable error message
    Position Position // Location in source
    Path     string   // JSON path (e.g., "wheres[0].field")
    Code     string   // Error code (e.g., "E120")
    Source   string   // Problematic source text
}
Position
type Position struct {
    Line      int // 1-based line number
    Column    int // 1-based column number
    Offset    int // 0-based byte offset
    EndLine   int // 1-based end line
    EndColumn int // 1-based end column
    EndOffset int // 0-based end byte offset
}

Error Codes

Code Description
E001 JSON parse error
E002 Expression parse error (panic recovered)
E100 Missing select field
E101 Invalid select expression
E110 Missing from field
E111 Invalid from/table name
E120 Invalid where condition
E130 Invalid order specification
E140 Invalid group specification
E150 Havings without groups
E151 Invalid having condition
E160 Invalid union query
E170 Join missing key
E171 Join missing foreign
E172 Join missing from
E180 SQL missing stmt
E190 Invalid subquery

Example Output

3:5-12:wheres[0]: error: Missing required field: field
5:3-8:orders[1]: error: Invalid sort value, must be 'asc' or 'desc'

Integration with AI Code Generation

When generating QueryDSL:

  1. Always validate generated DSL before use:
dsl, result := linter.Parse(generatedJSON)
if !result.Valid {
    // Return errors to AI for correction
    return result.FormatDiagnostics()
}
  1. Use error codes for programmatic handling:
for _, err := range result.Errors() {
    switch err.Code {
    case "E120":
        // Fix where condition
    case "E130":
        // Fix order specification
    }
}
  1. Leverage position info for precise fixes:
for _, err := range result.Errors() {
    fmt.Printf("Fix at line %d: %s\n", err.Position.Line, err.Message)
}

Test Assets

Test cases are located in ../assets/linter/:

  • valid/ - Valid DSL examples
  • invalid/ - Invalid DSL examples with expected errors
  • testcases.json - Test case metadata

Coverage

Current test coverage: 92.4%

Documentation

Index

Constants

View Source
const QueryDSLSchemaJSON = `` /* 7518-byte string literal not displayed */

QueryDSLSchemaJSON is the JSON Schema for QueryDSL as a string constant This is useful for MCP/LLM tool calls and validation

Expression Syntax (string):

  • field: "name", "table.name", "$model.name"
  • alias: "name as n", "field as 别名"
  • function: ":MAX(field)", ":COUNT(id)", ":SUM(amount)"
  • constant: "123", "0.618", "'string'"
  • encrypted: "field*"
  • object: "object$.foo", "object$.arr[0]"
  • array: "array[0]", "array[*]", "array@"
  • binding: "?:name", "?:extra.score"
  • type: "field(string 50)", "price(decimal 11,2)"

Table Syntax (string):

  • table: "users", "users as u"
  • model: "$user", "$user as u"

Condition Syntax (object):

  • standard: { "field": "score", "op": "=", "value": 20 }
  • shorthand: { "field": "score", "=": 20 }
  • field shorthand: { ":score": "comment", "=": 20 }
  • or condition: { "or": true, "field": "name", "=": "test" }
  • or shorthand: { "or :name": "comment", "=": "test" }
  • value expression: { "field": "a", "=": "{b}" }

Orders Syntax:

  • string array: ["id desc", "name asc"]
  • object array: [{"field": "id", "sort": "desc"}]

Groups Syntax:

  • string: "kind, city rollup 所有城市"
  • string array: ["kind", "city rollup 所有城市"]
  • object array: [{"field": "kind"}, {"field": "city", "rollup": "所有城市"}]

Variables

This section is empty.

Functions

func MustParse

func MustParse(source string) *gou.QueryDSL

MustParse parses a DSL string and panics if validation fails. Returns the parsed QueryDSL directly for convenience.

func QueryDSLSchema

func QueryDSLSchema() map[string]interface{}

QueryDSLSchema returns the JSON Schema for QueryDSL as a map

func ValidateSchema

func ValidateSchema(data interface{}) error

ValidateSchema validates data against the QueryDSL JSON Schema Returns nil if valid, error with validation details otherwise

func Validator

func Validator() (*goujson.Validator, error)

Validator returns a JSON Schema validator for QueryDSL

Types

type Diagnostic

type Diagnostic struct {
	Severity Severity `json:"severity"` // Error severity level
	Message  string   `json:"message"`  // Human-readable error message
	Position Position `json:"position"` // Location in source
	Path     string   `json:"path"`     // JSON path to the error (e.g., "wheres[0].field")
	Code     string   `json:"code"`     // Error code for programmatic handling
	Source   string   `json:"source"`   // The problematic source text
}

Diagnostic represents a single validation error or warning

func (Diagnostic) String

func (d Diagnostic) String() string

String returns a human-readable diagnostic string

type LintResult

type LintResult struct {
	DSL         *gou.QueryDSL `json:"dsl,omitempty"` // Parsed DSL (nil if parsing failed)
	Diagnostics []Diagnostic  `json:"diagnostics"`   // All diagnostics found
	Source      string        `json:"-"`             // Original source
	Valid       bool          `json:"valid"`         // True if no errors (warnings allowed)
	// contains filtered or unexported fields
}

LintResult contains the complete result of parsing and validating a DSL

func Lint

func Lint(source string) *LintResult

Lint validates a DSL string and returns only the LintResult. Use Parse() if you need both the DSL and validation result.

func Parse

func Parse(source string) (dsl *gou.QueryDSL, result *LintResult)

Parse parses a JSON DSL string and returns the parsed DSL and LintResult. If validation passes (no errors), the returned DSL can be used directly. Returns: (*gou.QueryDSL, *LintResult) - DSL is nil if parsing/validation failed

func (*LintResult) Errors

func (r *LintResult) Errors() []Diagnostic

Errors returns only error-level diagnostics

func (*LintResult) FormatDiagnostics

func (r *LintResult) FormatDiagnostics() string

FormatDiagnostics returns a formatted string of all diagnostics

func (*LintResult) HasErrors

func (r *LintResult) HasErrors() bool

HasErrors returns true if there are any error-level diagnostics

func (*LintResult) Warnings

func (r *LintResult) Warnings() []Diagnostic

Warnings returns only warning-level diagnostics

type Position

type Position struct {
	Line      int `json:"line"`       // 1-based line number
	Column    int `json:"column"`     // 1-based column number
	Offset    int `json:"offset"`     // 0-based byte offset
	EndLine   int `json:"end_line"`   // 1-based end line number
	EndColumn int `json:"end_column"` // 1-based end column number
	EndOffset int `json:"end_offset"` // 0-based end byte offset
}

Position represents a location in the source DSL

func (Position) String

func (p Position) String() string

String returns a human-readable position string

type Severity

type Severity int

Severity represents the severity level of a diagnostic

const (
	// SeverityError indicates an error that prevents query execution
	SeverityError Severity = iota
	// SeverityWarning indicates a potential issue that might cause problems
	SeverityWarning
	// SeverityInfo indicates informational messages
	SeverityInfo
	// SeverityHint indicates suggestions for improvement
	SeverityHint
)

func (Severity) String

func (s Severity) String() string

String returns the string representation of severity

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL