A middle ground between Go packages sqlx and sqlc.
This project aims to strike a balance between sqlx and sqlc.
It helps prevent human errors when working with raw SQL queries in code, as with sqlx, while avoiding the steep learning curve introduced by additional syntax, as seen in sqlc.
The sql-parser generates types based on schemas defined in SQL files and creates functions based on queries, using function names specified in comments.
During this process, it performs syntax validation and notifies users if any errors are found.
make sqlparser
# or
go run ./cmd/sqlparser \
-schema infra/mysql/schema.sql \
-query infra/mysql/query.sql \
-out infra/mysql \
-package sqlgenAll checks run before code generation. Every error is collected and reported at once.
| Category | Check | Description |
|---|---|---|
| Schema | Syntax validation | Validates each CREATE TABLE statement using the TiDB MySQL parser |
| Query | Syntax validation | Validates each query statement using the TiDB MySQL parser |
| Query | Table existence | Checks that tables referenced in FROM/JOIN/UPDATE/INTO are defined in the schema |
| Query | Column-table membership | Resolves aliases from the AST and verifies each column belongs to its referenced table |
| Query | Ambiguous column detection | Warns when a column name exists in multiple joined tables and is referenced without a table prefix |
| Query | Function existence | Checks that functions called in SQL exist in the MySQL built-in function list |
| Query | Annotation format | Validates that each -- name: line matches the -- name: <Name> :<one|many|exec> format |
| Query | Duplicate query names | Detects duplicate -- name: declarations |
| Query | Skipped query detection | Separately validates queries that were skipped in parseQueries due to table detection failure |
| Check | Difficulty | Description |
|---|---|---|
| Column type mismatch | High | Use schema type info to validate type compatibility in WHERE/SET clauses |
| EXPLAIN-based analysis | High | Connect to DB and validate query plans via EXPLAIN (e.g. missing indexes) |
| Schema change impact | High | Check existing query compatibility when schema changes (similar to sqlc verify) |
The only comment the parser interprets is the -- name: annotation.
Each query block must begin with a comment in the following format:
-- name: <QueryName> :<one|many|exec>Examples:
-- name: FindUserByUserID :one
-- name: ListUsers :many
-- name: UpdatePlayerName :execThe kind values mean:
one: returns a single rowmany: returns multiple rowsexec: executes a statement with no rows returned (INSERT/UPDATE/DELETE, etc.)
- Only
-- name:lines are interpreted by the parser. - All other
-- ...comments are ignored during parsing and code generation.parseQueries()skips--lines within query bodiesparseSchema()skips--lines withinCREATE TABLEbodies
validator.go checks the following:
- Each
-- name:line exactly matches the-- name: <Name> :<one|many|exec>format - No query name is declared more than once
- Write
-- name:on its own line - The kind must be one of
one,many, orexec - A typo or missing annotation will cause the query to be excluded from code generation or trigger a validation error