Skip to content

zoobz-io/astql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

astql

CI Coverage Go Report Card CodeQL Go Reference License Go Version Release

Type-safe SQL query builder with DBML schema validation.

Build queries as an AST, validate against your schema, render to parameterized SQL.

Injection-safe SQL Expressions, Any Dialect

instance.T("users")      // ✓ exists in schema
instance.T("uusers")     // panic: table "uusers" not found

instance.F("email")      // ✓ exists in schema
instance.F("emial")      // panic: field "emial" not found

query := astql.Select(instance.T("users")).
    Fields(instance.F("username"), instance.F("email")).
    Where(instance.C(instance.F("active"), astql.EQ, instance.P("is_active")))

result, _ := query.Render(postgres.New())
// SELECT "username", "email" FROM "users" WHERE "active" = :is_active

Typos become compile-time failures, not runtime surprises. Values are parameterized. Identifiers are quoted. The schema is the source of truth.

Same query, different databases:

import (
    "github.com/zoobz-io/astql/postgres"
    "github.com/zoobz-io/astql/sqlite"
    "github.com/zoobz-io/astql/mariadb"
    "github.com/zoobz-io/astql/mssql"
)

result, _ := query.Render(postgres.New())  // "username", LIMIT 10
result, _ := query.Render(sqlite.New())    // "username", LIMIT 10
result, _ := query.Render(mariadb.New())   // `username`, LIMIT 10
result, _ := query.Render(mssql.New())     // [username], TOP 10

One AST. Four dialects. Each renderer handles identifier quoting, pagination syntax, vendor-specific operators.

Install

go get github.com/zoobz-io/astql
go get github.com/zoobz-io/dbml

Requires Go 1.24+.

Quick Start

package main

import (
    "fmt"
    "github.com/zoobz-io/astql"
    "github.com/zoobz-io/astql/postgres"
    "github.com/zoobz-io/dbml"
)

func main() {
    // Define schema
    project := dbml.NewProject("myapp")
    users := dbml.NewTable("users")
    users.AddColumn(dbml.NewColumn("id", "bigint"))
    users.AddColumn(dbml.NewColumn("username", "varchar"))
    users.AddColumn(dbml.NewColumn("email", "varchar"))
    users.AddColumn(dbml.NewColumn("active", "boolean"))
    project.AddTable(users)

    // Create instance
    instance, err := astql.NewFromDBML(project)
    if err != nil {
        panic(err)
    }

    // Build and render
    result, err := astql.Select(instance.T("users")).
        Fields(instance.F("username"), instance.F("email")).
        Where(instance.C(instance.F("active"), astql.EQ, instance.P("is_active"))).
        OrderBy(instance.F("username"), astql.ASC).
        Limit(10).
        Render(postgres.New())

    if err != nil {
        panic(err)
    }

    fmt.Println(result.SQL)
    // SELECT "username", "email" FROM "users" WHERE "active" = :is_active ORDER BY "username" ASC LIMIT 10
    fmt.Println(result.RequiredParams)
    // [is_active]
}

Capabilities

Feature Description Docs
Schema Validation Tables and fields checked against DBML at build time Schema Validation
Multi-Dialect PostgreSQL, SQLite, MariaDB, MSSQL from one AST Architecture
Parameterized Values Injection-resistant queries with named parameters Conditions
Composable Queries Subqueries, JOINs, aggregates, window functions Joins
CASE Expressions Conditional logic within queries API

Why ASTQL?

  • Schema-validatedT("users") and F("email") checked against DBML at build time
  • Injection-resistant — parameterized values, quoted identifiers, no string concatenation
  • Multi-dialect — one query, four databases
  • Composable — subqueries, JOINs, aggregates, window functions, CASE expressions

Schema-First Data Access

ASTQL enables a pattern: define schema once in DBML, generate everything else.

Your DBML becomes the single source of truth. Downstream tools consume the schema to build:

  • Type-safe repositories — generated data access layers with cereal
  • Query builders — domain-specific methods that can't reference invalid columns
  • Multi-database applications — same business logic, swappable storage backends
// Schema defines what's valid
project := dbml.ParseFile("schema.dbml")
instance, _ := astql.NewFromDBML(project)

// Queries are structurally correct by construction
users := instance.T("users")
query := astql.Select(users).
    Fields(instance.F("id"), instance.F("email")).
    Where(instance.C(instance.F("active"), astql.EQ, instance.P("active")))

// Render to any supported database
sql, _ := query.Render(postgres.New())  // production
sql, _ := query.Render(sqlite.New())    // testing

The schema guards the boundary. Queries inside the boundary are safe by construction.

Documentation

Learn

  • Quickstart — get started in minutes
  • Concepts — tables, fields, params, conditions, builders
  • Architecture — AST structure, render pipeline, security layers

Guides

  • Schema Validation — DBML integration and validation
  • Conditions — WHERE, AND/OR, subqueries, BETWEEN
  • Joins — INNER, LEFT, RIGHT, CROSS joins
  • Aggregates — GROUP BY, HAVING, window functions
  • Testing — testing patterns for query builders

Cookbook

Reference

  • API — complete function documentation
  • Operators — all comparison and special operators

Contributing

See CONTRIBUTING.md for guidelines. For security issues, see SECURITY.md.

License

MIT — see LICENSE.

About

Type-safe SQL query builder with DBML schema validation

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Contributors