Documentation
¶
Overview ¶
Package schema provides schema-aware SQL validation for GoSQLX.
The package defines a hierarchy of Schema, Table, Column, and Catalog types that represent a relational database schema. A Validator created from a Schema (or Catalog) walks the AST produced by the GoSQLX parser and reports semantic errors such as references to non-existent tables or columns, ambiguous cross-schema column references, and INSERT column-count mismatches. Schemas can be built programmatically or loaded from DDL (CREATE TABLE) statements using GoSQLX's own parser via LoadFromDDL. All table and column lookups are case-insensitive to match SQL standard behaviour. For multi-schema environments the Catalog type resolves table references across schemas and returns a clear error when the same table name exists in more than one schema.
Example - Programmatic schema building:
s := schema.NewSchema("mydb")
t := schema.NewTable("users")
t.AddColumn(&schema.Column{Name: "id", DataType: "INT", Nullable: false})
t.AddColumn(&schema.Column{Name: "name", DataType: "VARCHAR(100)", Nullable: false})
s.AddTable(t)
v := schema.NewValidator(s)
errors, err := v.Validate("SELECT id, name FROM users")
Example - Loading schema from DDL:
ddl := `CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100) NOT NULL);`
s, err := schema.LoadFromDDL(ddl)
if err != nil {
log.Fatal(err)
}
v := schema.NewValidator(s)
errors, _ := v.Validate("SELECT email FROM users")
// errors[0].Message: column "email" does not exist in table "users"
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Catalog ¶
Catalog represents a database catalog containing multiple schemas (databases). It allows cross-schema query validation and catalog-level operations.
Example:
cat := schema.NewCatalog()
s1 := schema.NewSchema("app_db")
s2 := schema.NewSchema("audit_db")
cat.AddSchema(s1)
cat.AddSchema(s2)
cat.DefaultSchema = "app_db"
func LoadCatalogFromDDL ¶
LoadCatalogFromDDL parses DDL statements from sql and builds a Catalog. It handles CREATE TABLE, ALTER TABLE (ADD/DROP/RENAME COLUMN), and CREATE SCHEMA statements. Multiple schemas can be separated by "USE schema_name;" or by prefixing table names with "schema.table". Non-DDL statements are silently ignored.
Example:
ddl := ` CREATE TABLE app.users (id INT PRIMARY KEY, name VARCHAR(100) NOT NULL); CREATE TABLE audit.events (id INT, user_id INT, action VARCHAR(50)); ALTER TABLE app.users ADD COLUMN email VARCHAR(255); ` cat, err := schema.LoadCatalogFromDDL(ddl)
func LoadCatalogFromDDLFile ¶
LoadCatalogFromDDLFile reads a file and calls LoadCatalogFromDDL.
func (*Catalog) AddSchema ¶
AddSchema adds (or replaces) a schema in the catalog. Lookups are case-insensitive.
func (*Catalog) GetDefaultSchema ¶
GetDefaultSchema returns the default schema of the catalog. If DefaultSchema is set, it is used. Otherwise the single schema is returned when there is exactly one, and nil/false is returned for empty or ambiguous catalogs.
func (*Catalog) ResolveTable ¶
ResolveTable looks up a table by name across the catalog. It first searches the default schema, then every other schema.
When no default schema is set and the same table name exists in more than one schema, ResolveTable returns an ambiguity error so callers are never silently handed the wrong table:
ambiguous table reference: 'users' exists in multiple schemas [app, audit]; qualify with schema name
Returns the owning schema, the table, and nil error when found unambiguously. Returns nil, nil, nil when the table does not exist in any schema. Returns nil, nil, error when the reference is ambiguous.
func (*Catalog) SchemaNames ¶
SchemaNames returns a sorted list of all schema names in the catalog.
type CatalogValidator ¶
type CatalogValidator struct {
Catalog *Catalog
}
CatalogValidator validates SQL queries against a full Catalog (multi-schema). It supports all the same checks as Validator plus cross-schema resolution.
Example:
cat, _ := schema.LoadCatalogFromDDL(ddl)
cv := schema.NewCatalogValidator(cat)
errors, err := cv.Validate("SELECT id, name FROM users WHERE bogus = 1")
func NewCatalogValidator ¶
func NewCatalogValidator(cat *Catalog) *CatalogValidator
NewCatalogValidator creates a CatalogValidator for the given catalog.
func (*CatalogValidator) Validate ¶
func (cv *CatalogValidator) Validate(sql string) ([]ValidationError, error)
Validate parses the SQL string and validates it against the catalog.
func (*CatalogValidator) ValidateAST ¶
func (cv *CatalogValidator) ValidateAST(tree *ast.AST) []ValidationError
ValidateAST validates a parsed AST against the catalog.
type Column ¶
type Column struct {
Name string
DataType string
Nullable bool
Default string
References *ForeignKeyRef // if this column references another table
}
Column represents a table column.
type ForeignKey ¶
ForeignKey represents a foreign key constraint.
type ForeignKeyRef ¶
ForeignKeyRef is a column-level FK reference.
type Schema ¶
Schema represents a database schema with tables, columns, and constraints.
func LoadFromDDL ¶
LoadFromDDL parses CREATE TABLE statements from the given SQL string and builds a Schema. Multiple CREATE TABLE statements can be included in the input, separated by semicolons or newlines. Non-CREATE TABLE statements are silently ignored.
Example:
ddl := `
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT REFERENCES users(id),
total DECIMAL(10,2)
);
`
schema, err := LoadFromDDL(ddl)
func LoadFromDDLFile ¶
LoadFromDDLFile reads a file at the given path and loads schema from the DDL statements contained within it.
func (*Schema) AddTable ¶
AddTable adds a table to the schema. If a table with the same name already exists, it is replaced. Tables are stored with their original name but lookups are case-insensitive.
func (*Schema) GetTable ¶
GetTable looks up a table by name. Returns the table and true if found, or nil and false if not found. The lookup is case-insensitive.
func (*Schema) TableNames ¶
TableNames returns a sorted list of all table names in the schema, using the original names from the Table structs.
type Table ¶
type Table struct {
Name string
Columns map[string]*Column
PrimaryKey []string
ForeignKeys []ForeignKey
Indexes []Index
}
Table represents a database table.
func (*Table) AddColumn ¶
AddColumn adds a column to the table. If a column with the same name already exists, it is replaced. Columns are stored with their original name but lookups are case-insensitive.
func (*Table) ColumnNames ¶
ColumnNames returns a sorted list of all column names in the table, using the original names from the Column structs.
type TypeCategory ¶
type TypeCategory int
TypeCategory represents a broad category of SQL data types for compatibility checking.
const ( TypeCategoryUnknown TypeCategory = iota TypeCategoryNumeric TypeCategoryString TypeCategoryDateTime TypeCategoryBoolean )
type ValidationError ¶
type ValidationError struct {
Message string // Human-readable description of the issue
Line int // Line number (1-based, 0 if unknown)
Column int // Column number (1-based, 0 if unknown)
Severity string // "error" or "warning"
Suggestion string // Optional suggestion for how to fix the issue
}
ValidationError represents a single validation issue found in a SQL query. Note: Line and Column are populated when position information is available from AST nodes. Currently, most AST nodes do not carry position data, so these fields will be 0 for most errors. Future AST enhancements will enable precise source location tracking.
func ValidateQuery ¶
func ValidateQuery(tree *ast.AST, cat *Catalog) []ValidationError
ValidateQuery validates a pre-parsed AST against an explicit catalog. This is a convenience function for when the caller already has both.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
Error returns a human-readable string for the validation error.
type Validator ¶
type Validator struct {
Schema *Schema
}
Validator validates SQL queries against a schema.
func NewValidator ¶
NewValidator creates a new Validator for the given schema.
func (*Validator) Validate ¶
func (v *Validator) Validate(sql string) ([]ValidationError, error)
Validate parses a SQL query and validates it against the schema. Returns a slice of validation errors (which may be empty if valid) and an error if parsing fails.
func (*Validator) ValidateAST ¶
func (v *Validator) ValidateAST(tree *ast.AST) []ValidationError
ValidateAST checks a parsed AST against the schema and returns any validation errors found.
func (*Validator) ValidateForeignKeys ¶
func (v *Validator) ValidateForeignKeys() []ValidationError
ValidateForeignKeys checks that all foreign key references in the schema point to valid tables and columns. This is a schema-level check that can be called independently of query validation.
func (*Validator) ValidateSelectFull ¶
func (v *Validator) ValidateSelectFull(sql string) ([]ValidationError, error)
ValidateSelectFull performs full SELECT validation including ORDER BY and GROUP BY aggregate semantics via the existing single-schema Validator. This makes the enhanced validation available without requiring a Catalog.