syntaqlite 0.0.3

Parser, formatter, validator, and language server for SQLite SQL — built on SQLite's own grammar
Documentation

Fast, accurate SQL tooling for SQLite and its dialects.

This crate provides parsing, formatting, and semantic validation for SQL, built on SQLite's own tokenizer and grammar rules. Four design principles guide the library:

  • Reliability — uses SQLite's own grammar rules; formatting is round-trip safe and validation mirrors real engine behaviour.
  • Speed — all core types ([Formatter], [SemanticAnalyzer], [Catalog]) are designed for reuse across many inputs without re-allocation.
  • Portability — the core formatting and validation engine has no runtime dependencies beyond the standard library; optional features (lsp, serde) pull in additional crates.
  • Flexibility — supports multiple database dialects that extend SQLite's grammar with their own tokens and rules.

Parsing

Use Parser to parse SQL source text into a typed AST:

use syntaqlite::parse::ParseErrorKind;
use syntaqlite::{Parser, ParseOutcome};

let parser = Parser::new();
let mut session = parser.parse("SELECT 1; SELECT 2");
loop {
    match session.next() {
        ParseOutcome::Ok(stmt) => println!("{:?}", stmt.root()),
        ParseOutcome::Err(e) => {
            eprintln!("parse error: {}", e.message());
            if e.kind() == ParseErrorKind::Fatal { break; }
        }
        ParseOutcome::Done => break,
    }
}

See the [parse] module for additional types like IncrementalParseSession, ParserConfig, and ParserToken.

Validation

Use [SemanticAnalyzer] to check SQL against a known schema. The analyzer produces a SemanticModel containing structured [Diagnostic] values with byte-offset spans and "did you mean?" suggestions.

use syntaqlite::semantic::CatalogLayer;
use syntaqlite::{
    SemanticAnalyzer, Catalog, ValidationConfig, sqlite_dialect,
};

let mut analyzer = SemanticAnalyzer::new();
let mut catalog = Catalog::new(sqlite_dialect());

// Register a table so the analyzer can resolve column references.
catalog.layer_mut(CatalogLayer::Database)
    .insert_table("users", Some(vec!["id".into(), "name".into()]), false);

let config = ValidationConfig::default();
let model = analyzer.analyze("SELECT id, name FROM users", &catalog, &config);

// All names resolve — no diagnostics.
assert!(model.diagnostics().is_empty());

For richer output, use DiagnosticRenderer to produce rustc-style error messages with source context and underlines.

Formatting

Use [Formatter] to pretty-print SQL with consistent style. The formatter parses each statement, runs a bytecode interpreter over the AST, and renders the result with a Wadler-style pretty-printer.

# use syntaqlite::fmt::KeywordCase;
# use syntaqlite::{Formatter, FormatConfig};
let mut fmt = Formatter::with_config(
    &FormatConfig::default()
        .with_keyword_case(KeywordCase::Lower)
        .with_line_width(60),
);

let output = fmt.format("select id,name from users where active=1").unwrap();
assert!(output.starts_with("select"));
assert!(output.contains("from"));

See [FormatConfig] for all available options (line width, indent width, keyword casing, semicolons).

Features

  • sqlite (default): enables the built-in SQLite grammar, [Dialect], and re-exports Parser, Tokenizer, and typed AST [nodes].
  • fmt (default): enables [Formatter], [FormatConfig], and KeywordCase.
  • validation (default): enables [SemanticAnalyzer], [Catalog], [Diagnostic], and related types.
  • lsp: enables LspServer and [lsp::LspHost] for editor integration.
  • experimental-embedded: enables [embedded] SQL extraction from Python and TypeScript/JavaScript source files.
  • serde: adds Serialize/Deserialize impls for diagnostics and AST nodes.
  • serde-json: adds JSON convenience helpers (catalog from JSON, AST dump).

Choosing an API

  • Use Parser and Tokenizer for parsing and tokenizing SQL.
  • Use [SemanticAnalyzer] + [Catalog] when you need to validate SQL against a database schema (table/column/function resolution).
  • Use [Formatter] when you need to pretty-print or normalize SQL text.
  • Use LspServer (requires the lsp feature) to embed a full Language Server Protocol implementation in an editor or tool.
  • Use [typed] when building reusable code over known generated grammars.
  • Use [any] when grammar choice happens at runtime or crosses FFI/plugin boundaries.