qrafter

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 25, 2026 License: MIT Imports: 12 Imported by: 0

README

qrafter

Go Reference Go CI

qrafter is a small type-safe SQL query builder for Go - no ORM, no codegen, just typed SQL-shaped Go.

qrafter helps you build parameterized SQL from typed Go table structs. You define tables once, compose queries from typed columns, and render SQL plus driver arguments for database/sql, sqlx, and similar packages.

It is designed for Go developers who want to keep SQL explicit, but avoid hand-writing fragile column names, placeholders, and query fragments.

Why qrafter?

Use qrafter when you want:

  • Typed table and column references with qrafter.Column[T]
  • SQL that still looks and feels like SQL
  • Parameterized queries instead of interpolated user values
  • Dialect-aware identifier quoting and placeholders
  • Compatibility with your existing database driver and connection pool
  • A lightweight query builder instead of a full ORM
  • No code generation step in your build workflow

qrafter is probably not the right fit if you want schema migrations, model lifecycle hooks, relationship loading, or an ORM that hides SQL from application code.

Install

go get github.com/SennovE/qrafter

Quick start

package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type User struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[User]()

	sql, args, err := q.Select(users.ID, users.UserName).
		Where(
			users.Age.Ge(18),
			users.UserName.Eq("Alice"),
		).
		OrderBy(users.ID.Asc()).
		Limit(10).
		Render(dialect.PostgreSQL{})
	if err != nil {
		panic(err)
	}

	fmt.Println(sql)
	fmt.Println(args)
}

Output:

SELECT "users"."id", "users"."user_name"
FROM "users"
WHERE "users"."age" >= $1 AND "users"."user_name" = $2
ORDER BY "users"."id" ASC
LIMIT 10
[18 Alice]

How it works

A qrafter table is a Go struct with typed column fields:

type User struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

q.MustNewTable[User]() binds the struct fields to SQL table and column names. Queries are then composed from those typed columns and rendered for a selected SQL dialect.

Field names are converted into column names automatically, or you can override them with db tags.

When to use it

qrafter is useful when you want typed query composition while still keeping control over the generated SQL.

Good fits:

  • services that already use database/sql or sqlx
  • projects that prefer explicit SQL over ORM abstractions
  • codebases where query fragments need to be composed safely
  • applications that want typed table and column references without codegen

Less ideal fits:

  • projects that want a full ORM
  • applications that expect automatic relationship loading
  • teams that prefer writing raw SQL files and generating Go code from them
  • projects that need schema migrations as part of the same tool

Features

  • Typed table structs with qrafter.Column[T]
  • Table configuration via embedded qrafter.Table or TableConfig()
  • Automatic column binding from field names or db tags
  • Custom field-to-column mapping through qrafter.NameMapper
  • Dialect-aware identifier quoting and placeholders
  • Human-readable multiline SQL rendering
  • Parameterized SELECT, joins, grouping, ordering, limits, and offsets
  • Parameterized INSERT with VALUES, DEFAULT VALUES, INSERT ... SELECT, and RETURNING
  • Parameterized UPDATE with SET, FROM, WHERE, CTEs, and RETURNING
  • Parameterized DELETE with WHERE, USING, CTEs, and RETURNING
  • CTEs and recursive CTEs
  • Compound queries such as UNION and UNION ALL
  • Aggregates and window functions
  • DDL builders for tables, columns, constraints, and indexes
  • database/sql and sqlx-friendly scanning helpers

DDL

Schema statements live in the separate ddl package so the root package can stay focused on query building:

sql, err := ddl.CreateTable(users).
	Columns(
		ddl.Column(users.ID, ddl.BigSerial()).PrimaryKey(),
		ddl.Column(users.Email, ddl.Text()).NotNull().Unique(),
		ddl.Column(users.CreatedAt, ddl.TimestampTZ()).DefaultExpr("now()"),
	).
	Render(dialect.PostgreSQL{})

DDL rendering returns an error when a dialect cannot safely render a requested feature, such as SQLite column type changes or MySQL partial indexes.

When using FromModel(), column types are inferred from qrafter.Column[T] and can be overridden with a field tag:

type User struct {
	q.Table `table:"users"`

	ID    q.Column[int64]  `db:"id"`
	Email q.Column[string] `db:"email" ddl:"VARCHAR(320)"`
}

users := q.MustNewTable[User]()
sql, err := ddl.CreateTable(users).FromModel().Render(dialect.PostgreSQL{})

Dialects

qrafter currently includes:

  • dialect.BaseDialect for ANSI-style double-quoted identifiers and ? placeholders
  • dialect.PostgreSQL for PostgreSQL-style $1, $2, ... placeholders
  • dialect.MySQL for backtick-quoted identifiers, MySQL LIMIT/OFFSET, empty-row inserts, multi-table UPDATE/DELETE, and NULL ordering emulation
  • dialect.SQLite for SQLite literals, LIMIT/OFFSET, and fail-fast handling for unsupported DELETE USING

Dialect support is built from small rendering hooks. New dialects can start with identifier quoting, literals, placeholders, and LIMIT/OFFSET, then override focused feature hooks for clauses such as RETURNING, UPDATE sources, DELETE sources, joins, default inserts, and NULL ordering.

New dialects can be added by implementing dialect.Renderer.

Comparison

Approach Good when Tradeoff
Raw database/sql You want full control over every query SQL strings, placeholders, and column names are maintained manually
SQL code generation You want generated Go code from SQL files Adds a generation step and a SQL-first workflow
ORM You want high-level model and relationship management SQL can become less explicit and harder to control
qrafter You want typed SQL-shaped Go without ORM or codegen It is a lightweight query builder, not a full database framework

Project status

qrafter is pre-v1. The API may still change while the package evolves.

Feedback is especially welcome around:

  • API naming
  • query composition ergonomics
  • dialect support
  • real-world usage with database/sql and sqlx

Contributing

Contributions are welcome. See CONTRIBUTING.md for the local development workflow and pull request guidelines.

Good first areas to explore:

  • Add examples for common query patterns
  • Improve dialect coverage
  • Expand integration tests
  • Polish package documentation on pkg.go.dev

Documentation

Overview

Package qrafter builds dialect-aware SQL queries from typed Go table structs.

A table model is a struct with Column fields and either a TableConfig method or an embedded Table tagged with table:"table_name". NewTable binds those fields to SQL column names, and the query builders render SQL plus driver arguments for a selected dialect.

A typical model looks like this:

type User struct {
	qrafter.Table `table:"users"`

	ID       qrafter.Column[int] `db:"id"`
	UserName qrafter.Column[string]
	Age      qrafter.Column[int]
}

Field names without db tags are mapped through NameMapper, which defaults to snake_case conversion. Override NameMapper before binding tables if your project uses a different naming convention.

SELECT construction is centered on Select. qrafter infers the FROM clause from the columns and predicates used in the query:

users := qrafter.MustNewTable[User]()

sql, args, err := qrafter.Select(users.ID, users.UserName).
	Where(users.Age.Ge(18), users.UserName.Eq("Alice")).
	OrderBy(users.ID.Asc()).
	Limit(10).
	Render(dialect.PostgreSQL{})
if err != nil {
	panic(err)
}

The rendered SQL uses dialect-specific identifier quoting, placeholders, and clause-level line breaks. For PostgreSQL, the example above renders:

SELECT "users"."id", "users"."user_name"
FROM "users"
WHERE "users"."age" >= $1 AND "users"."user_name" = $2
ORDER BY "users"."id" ASC
LIMIT 10

and returns []any{18, "Alice"} as driver arguments.

SELECT queries support:

  • WHERE predicates and AND/OR composition.
  • INNER, LEFT, RIGHT, FULL, and CROSS joins.
  • GROUP BY and HAVING.
  • ORDER BY with ASC, DESC, NULLS FIRST, and NULLS LAST.
  • LIMIT and OFFSET.
  • Parameterized values through Param and inline SQL literals through Literal.
  • Aggregate and function expressions, including DISTINCT arguments.
  • Window functions and frame clauses.
  • Common table expressions, recursive CTEs, UNION, and UNION ALL.

INSERT queries support:

  • Explicit target columns through Columns.
  • One or more VALUES rows through Values or ValuesRows.
  • Set-style single row construction through Set.
  • ValuesFrom for inserting values currently stored in Column fields on one table model.
  • ValuesRowsFrom for inserting values from a slice of table models.
  • DEFAULT VALUES and per-column DEFAULT expressions.
  • INSERT ... SELECT through FromSelect.
  • RETURNING expressions for dialects that support them.

UPDATE queries support:

  • SET assignments through Set or SetFrom.
  • WHERE predicates with parameterized values.
  • FROM tables, including automatic FROM inference from SET values and WHERE predicates.
  • Common table expressions referenced from FROM, assignments, or predicates.
  • RETURNING expressions for dialects that support them.

DELETE queries support:

  • DELETE FROM a typed table model.
  • WHERE predicates with parameterized values.
  • USING tables, including automatic USING inference from WHERE predicates.
  • Common table expressions referenced from USING or predicates.
  • RETURNING expressions for dialects that support them.

Columns can also scan values from database/sql rows, which lets the same struct describe both query construction and result destinations. The scan helpers work with database/sql and are friendly to sqlx struct mapping.

Index

Examples

Constants

This section is empty.

Variables

View Source
var NameMapper = utils.ToSnake

NameMapper maps Go struct field names to SQL column names when a field does not have a db tag. Set it before calling NewTable or MustNewTable.

Functions

func BindTableToCTE added in v0.3.0

func BindTableToCTE[T any](cte CommonTableExpression) (T, error)

BindTableToCTE binds a table model to the CTE's table reference.

func GetTableRef added in v0.2.0

func GetTableRef(table TableConfigProvider) core.TableRef

GetTableRef returns the SQL table reference for a table model.

func MustBindTableToCTE added in v0.3.0

func MustBindTableToCTE[T any](cte CommonTableExpression) T

MustBindTableToCTE is like BindTableToCTE but panics on failure.

func MustNewTable added in v0.3.0

func MustNewTable[T TableConfigProvider]() T

MustNewTable is like NewTable but panics if the table cannot be bound.

func NewTable added in v0.3.0

func NewTable[T TableConfigProvider]() (T, error)

NewTable creates a table model and binds its exported Column fields. Table configuration can come from a TableConfig method or an embedded Table field tagged with table:"table_name". Column names come from the field's db tag when present; otherwise the Go field name is mapped through NameMapper.

func ScanDest added in v0.3.0

func ScanDest(table any) ([]any, error)

ScanDest returns scan destinations for exported Column fields in a struct pointer.

Example
package main

import (
	"database/sql"
	"fmt"
	"log"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	db, err := sql.Open("postgres", "postgres://user:pass@localhost/app")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	user := q.MustNewTable[exampleUser]()
	query, _ := q.Select(user.ID, user.UserName, user.Age).MustRender(dialect.PostgreSQL{})

	rows, err := db.Query(query)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		dest, err := q.ScanDest(&user)
		if err != nil {
			log.Fatal(err)
		}
		if err := rows.Scan(dest...); err != nil {
			log.Fatal(err)
		}

		fmt.Println(user.ID.Get(), user.UserName.Get(), user.Age.Get())
	}
	if err := rows.Err(); err != nil {
		log.Fatal(err)
	}
}

func TableAlias

func TableAlias[T TableConfigProvider](table T, alias string) (T, error)

TableAlias returns a copy of a table model bound to a SQL alias.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[exampleUser]()
	managers, err := q.TableAlias(users, "manager")
	if err != nil {
		panic(err)
	}

	sql, _ := q.Select(users.UserName, managers.UserName).
		Join(managers, users.Age.Eq(managers.Age)).
		MustRender(dialect.PostgreSQL{})

	fmt.Println(sql)

}
Output:
SELECT "users"."user_name", "manager"."user_name"
FROM "users"
JOIN "users" AS "manager" ON "users"."age" = "manager"."age"

Types

type Aggregate added in v0.2.0

type Aggregate struct {
	Expression
}

Aggregate represents a SQL aggregate expression such as COUNT or SUM.

func AggregateFunc added in v0.2.0

func AggregateFunc(name string, args ...any) Aggregate

AggregateFunc builds an aggregate expression with the given function name.

func Avg added in v0.2.0

func Avg(v any) Aggregate

Avg builds an AVG aggregate expression.

func Count added in v0.2.0

func Count(args ...any) Aggregate

Count builds a COUNT aggregate expression.

func Max added in v0.2.0

func Max(v any) Aggregate

Max builds a MAX aggregate expression.

func Min added in v0.2.0

func Min(v any) Aggregate

Min builds a MIN aggregate expression.

func Sum added in v0.1.0

func Sum(v any) Aggregate

Sum builds a SUM aggregate expression.

func (Aggregate) Aggregate added in v0.2.0

func (a Aggregate) Aggregate()

Aggregate marks the value as an aggregate expression.

func (Aggregate) As added in v0.2.0

func (a Aggregate) As(alias string) Aggregate

As returns the aggregate expression with a SQL alias.

type Column added in v0.1.0

type Column[T any] struct {
	Expression
	// contains filtered or unexported fields
}

Column represents a typed SQL table column and a scan destination for values of type T.

func (*Column[T]) Bind added in v0.1.0

func (c *Column[T]) Bind(name string, table core.TableRef)

Bind attaches the column to a SQL name and table reference.

func (Column[T]) ColumnName added in v0.4.0

func (c Column[T]) ColumnName() string

ColumnName returns the SQL column name associated with the column.

func (Column[T]) Get added in v0.3.0

func (c Column[T]) Get() T

Get returns the column's scanned or assigned value.

func (*Column[T]) Ptr added in v0.3.0

func (c *Column[T]) Ptr() *T

Ptr returns a pointer to the column's value.

func (Column[T]) Render added in v0.1.0

func (c Column[T]) Render(w *strings.Builder, d dialect.Renderer)

Render writes the fully qualified column name.

func (*Column[T]) Scan added in v0.3.0

func (c *Column[T]) Scan(src any) error

Scan implements sql.Scanner for Column.

func (*Column[T]) Set added in v0.3.0

func (c *Column[T]) Set(value T)

Set assigns the column's value.

func (Column[T]) TableRef added in v0.2.0

func (c Column[T]) TableRef() core.TableRef

TableRef returns the table reference associated with the column.

func (Column[T]) Tables added in v0.1.0

func (c Column[T]) Tables() core.TablesSet

Tables returns the set containing the column's table reference.

func (Column[T]) Value added in v0.3.0

func (c Column[T]) Value() (driver.Value, error)

Value implements driver.Valuer for Column.

type ColumnRef added in v0.4.0

type ColumnRef interface {
	TableRefer
	ColumnName() string
}

ColumnRef identifies a concrete SQL column.

type CommonTableExpression added in v0.2.0

type CommonTableExpression struct {
	// contains filtered or unexported fields
}

CommonTableExpression represents a named SQL common table expression.

func (CommonTableExpression) CTEs added in v0.2.0

func (cte CommonTableExpression) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the CTE's query.

func (CommonTableExpression) Column added in v0.2.0

func (cte CommonTableExpression) Column(name string) Column[any]

Column returns an untyped column reference belonging to the CTE.

func (CommonTableExpression) Recursive added in v0.2.0

Recursive marks the CTE as recursive.

func (CommonTableExpression) Render added in v0.2.0

Render writes the CTE declaration.

func (CommonTableExpression) RenderQueryExpression added in v0.2.0

func (cte CommonTableExpression) RenderQueryExpression(w *strings.Builder, d dialect.Renderer)

RenderQueryExpression writes the CTE's underlying query expression.

func (CommonTableExpression) RenderSetOperand added in v0.2.0

func (cte CommonTableExpression) RenderSetOperand(w *strings.Builder, d dialect.Renderer)

RenderSetOperand writes the CTE's underlying query as a set operand.

func (CommonTableExpression) TableConfig added in v0.2.0

func (cte CommonTableExpression) TableConfig() TableConfig

TableConfig returns the table configuration for the CTE reference.

func (CommonTableExpression) TableRef added in v0.2.0

func (cte CommonTableExpression) TableRef() core.TableRef

TableRef returns the table reference used when querying the CTE.

func (CommonTableExpression) Union added in v0.2.0

Union combines the CTE query with another query using UNION.

func (CommonTableExpression) UnionAll added in v0.2.0

UnionAll combines the CTE query with another query using UNION ALL.

func (CommonTableExpression) WithColumns added in v0.2.0

func (cte CommonTableExpression) WithColumns(columns ...string) CommonTableExpression

WithColumns adds an explicit column list to the CTE declaration.

type CompoundQuery added in v0.2.0

type CompoundQuery struct {
	// contains filtered or unexported fields
}

CompoundQuery represents a set operation such as UNION or UNION ALL.

func (CompoundQuery) CTE added in v0.2.0

CTE wraps the compound query as a common table expression.

func (CompoundQuery) CTEs added in v0.2.0

func (q CompoundQuery) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the compound query.

func (CompoundQuery) Limit added in v0.2.0

func (q CompoundQuery) Limit(l int) CompoundQuery

Limit sets a final LIMIT clause on the compound query.

func (CompoundQuery) MustRender added in v0.5.0

func (q CompoundQuery) MustRender(d dialect.Renderer) (sql string, args []any)

MustRender is like Render but panics if the query is invalid.

func (CompoundQuery) Offset added in v0.2.0

func (q CompoundQuery) Offset(o int) CompoundQuery

Offset sets a final OFFSET clause on the compound query.

func (CompoundQuery) OrderBy added in v0.2.0

func (q CompoundQuery) OrderBy(items ...core.Selecter) CompoundQuery

OrderBy appends a final ORDER BY clause to the compound query.

func (CompoundQuery) RecursiveCTE added in v0.2.0

func (q CompoundQuery) RecursiveCTE(name string) CommonTableExpression

RecursiveCTE wraps the compound query as a recursive common table expression.

func (CompoundQuery) Render added in v0.2.0

func (q CompoundQuery) Render(d dialect.Renderer) (sql string, args []any, err error)

Render renders the query and returns SQL, bound arguments and an error if the query is invalid.

func (CompoundQuery) RenderQueryExpression added in v0.2.0

func (q CompoundQuery) RenderQueryExpression(w *strings.Builder, d dialect.Renderer)

RenderQueryExpression writes the compound query body.

func (CompoundQuery) RenderSetOperand added in v0.2.0

func (q CompoundQuery) RenderSetOperand(w *strings.Builder, d dialect.Renderer)

RenderSetOperand writes the compound query as a parenthesized set operand.

func (CompoundQuery) Union added in v0.2.0

Union combines this query with another query using UNION.

func (CompoundQuery) UnionAll added in v0.2.0

func (q CompoundQuery) UnionAll(other core.QueryExpression) CompoundQuery

UnionAll combines this query with another query using UNION ALL.

type DeleteQuery added in v0.4.0

type DeleteQuery struct {
	// contains filtered or unexported fields
}

DeleteQuery represents a DELETE statement under construction.

func Delete added in v0.4.0

func Delete(table TableConfigProvider) DeleteQuery

Delete starts a DELETE query for the given table.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[exampleUser]()

	sql, args := q.Delete(users).
		Where(users.Age.Lt(18)).
		Returning(users.ID).
		MustRender(dialect.PostgreSQL{})

	fmt.Println(sql)
	fmt.Println(args)

}
Output:
DELETE FROM "users"
WHERE "users"."age" < $1
RETURNING "users"."id"
[18]

func (DeleteQuery) CTEs added in v0.4.0

func (q DeleteQuery) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the DELETE query.

func (DeleteQuery) MustRender added in v0.5.0

func (q DeleteQuery) MustRender(d dialect.Renderer) (sql string, args []any)

MustRender is like Render but panics if the query is invalid.

func (DeleteQuery) Render added in v0.4.0

func (q DeleteQuery) Render(d dialect.Renderer) (sql string, args []any, err error)

Render renders the query and returns SQL, bound arguments and an error if the query is invalid.

func (DeleteQuery) RenderStatement added in v0.4.0

func (q DeleteQuery) RenderStatement(w *strings.Builder, d dialect.Renderer)

RenderStatement writes the DELETE query body.

func (DeleteQuery) Returning added in v0.4.0

func (q DeleteQuery) Returning(items ...core.Selecter) DeleteQuery

Returning appends expressions to a RETURNING clause.

func (DeleteQuery) Using added in v0.4.0

func (q DeleteQuery) Using(tables ...TableConfigProvider) DeleteQuery

Using appends tables to the DELETE USING clause.

func (DeleteQuery) Where added in v0.4.0

func (q DeleteQuery) Where(predicates ...core.Predicater) DeleteQuery

Where appends predicates to the DELETE WHERE clause.

type Expression added in v0.2.0

type Expression struct {
	// contains filtered or unexported fields
}

Expression represents a SQL value expression that can be selected or compared.

func Default added in v0.4.0

func Default() Expression

Default returns the SQL DEFAULT keyword for INSERT values.

func DenseRank added in v0.2.0

func DenseRank() Expression

DenseRank builds a DENSE_RANK window function expression.

func Distinct added in v0.2.0

func Distinct(v any) Expression

Distinct wraps an expression in DISTINCT.

func Func added in v0.2.0

func Func(name string, args ...any) Expression

Func builds a SQL function call expression.

func Lag added in v0.2.0

func Lag(v any, args ...any) Expression

Lag builds a LAG window function expression.

func Lead added in v0.2.0

func Lead(v any, args ...any) Expression

Lead builds a LEAD window function expression.

func Literal added in v0.2.0

func Literal(v any) Expression

Literal returns an expression rendered inline using the dialect's literal rules.

func Param added in v0.2.0

func Param(v any) Expression

Param returns an expression rendered as a placeholder with a bound argument.

func Rank added in v0.2.0

func Rank() Expression

Rank builds a RANK window function expression.

func RowNumber added in v0.2.0

func RowNumber() Expression

RowNumber builds a ROW_NUMBER window function expression.

func Star added in v0.2.0

func Star() Expression

Star returns a '*' expression.

func WindowFunc added in v0.2.0

func WindowFunc(name string, args ...any) Expression

WindowFunc builds a SQL window function expression.

func (Expression) Add added in v0.2.0

func (e Expression) Add(v any) Expression

Add returns an addition expression.

func (Expression) As added in v0.2.0

func (e Expression) As(alias string) Expression

As returns the expression with a SQL alias.

func (Expression) Asc added in v0.2.0

func (e Expression) Asc() Order

Asc returns an ascending ORDER BY expression.

func (Expression) Desc added in v0.2.0

func (e Expression) Desc() Order

Desc returns a descending ORDER BY expression.

func (Expression) Div added in v0.2.0

func (e Expression) Div(v any) Expression

Div returns a division expression.

func (Expression) Eq added in v0.2.0

func (e Expression) Eq(v any) Predicate

Eq returns an equality predicate.

func (Expression) Ge added in v0.2.0

func (e Expression) Ge(v any) Predicate

Ge returns a greater-than-or-equal predicate.

func (Expression) Gt added in v0.2.0

func (e Expression) Gt(v any) Predicate

Gt returns a greater-than predicate.

func (Expression) IsNotNull added in v0.5.0

func (e Expression) IsNotNull() Predicate

IsNotNull returns an IS NOT NULL predicate.

func (Expression) IsNull added in v0.5.0

func (e Expression) IsNull() Predicate

IsNull returns an IS NULL predicate.

func (Expression) Le added in v0.2.0

func (e Expression) Le(v any) Predicate

Le returns a less-than-or-equal predicate.

func (Expression) Lt added in v0.2.0

func (e Expression) Lt(v any) Predicate

Lt returns a less-than predicate.

func (Expression) Mul added in v0.2.0

func (e Expression) Mul(v any) Expression

Mul returns a multiplication expression.

func (Expression) Over added in v0.2.0

func (e Expression) Over(specs ...WindowSpec) Expression

Over returns an expression with an OVER clause.

func (Expression) Precedence added in v0.2.0

func (e Expression) Precedence() int

Precedence returns the expression precedence used for parenthesizing SQL.

func (Expression) Render added in v0.2.0

func (e Expression) Render(w *strings.Builder, d dialect.Renderer)

Render writes the SQL representation of the expression.

func (Expression) Sub added in v0.2.0

func (e Expression) Sub(v any) Expression

Sub returns a subtraction expression.

func (Expression) Tables added in v0.2.0

func (e Expression) Tables() core.TablesSet

Tables returns table references used by the expression.

type InsertQuery added in v0.4.0

type InsertQuery struct {
	// contains filtered or unexported fields
}

InsertQuery represents an INSERT statement under construction.

func Insert added in v0.4.0

func Insert(table TableConfigProvider) InsertQuery

Insert starts an INSERT query for the given table.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[exampleUser]()

	sql, args := q.Insert(users).
		Columns(users.UserName, users.Age).
		Values("Alice", 18).
		Returning(users.ID).
		MustRender(dialect.PostgreSQL{})

	fmt.Println(sql)
	fmt.Println(args)

}
Output:
INSERT INTO "users" ("user_name", "age")
VALUES ($1, $2)
RETURNING "users"."id"
[Alice 18]

func (InsertQuery) CTEs added in v0.4.0

func (q InsertQuery) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the INSERT source.

func (InsertQuery) Columns added in v0.4.0

func (q InsertQuery) Columns(columns ...ColumnRef) InsertQuery

Columns appends the target column list for the INSERT.

func (InsertQuery) DefaultValues added in v0.4.0

func (q InsertQuery) DefaultValues() InsertQuery

DefaultValues makes the INSERT use DEFAULT VALUES.

func (InsertQuery) FromSelect added in v0.4.0

func (q InsertQuery) FromSelect(source core.QueryExpression) InsertQuery

FromSelect makes the INSERT read rows from a SELECT or compound query.

func (InsertQuery) MustRender added in v0.5.0

func (q InsertQuery) MustRender(d dialect.Renderer) (sql string, args []any)

MustRender is like Render but panics if the query is invalid.

func (InsertQuery) Render added in v0.4.0

func (q InsertQuery) Render(d dialect.Renderer) (sql string, args []any, err error)

Render renders the query and returns SQL, bound arguments and an error if the query is invalid.

func (InsertQuery) RenderStatement added in v0.4.0

func (q InsertQuery) RenderStatement(w *strings.Builder, d dialect.Renderer)

RenderStatement writes the INSERT query body.

func (InsertQuery) Returning added in v0.4.0

func (q InsertQuery) Returning(items ...core.Selecter) InsertQuery

Returning appends expressions to a RETURNING clause.

func (InsertQuery) Set added in v0.4.0

func (q InsertQuery) Set(column ColumnRef, value any) InsertQuery

Set appends a target column and value to the current VALUES row.

func (InsertQuery) Values added in v0.4.0

func (q InsertQuery) Values(values ...any) InsertQuery

Values appends a VALUES row. Plain Go values are rendered as bound arguments; use Literal for inline SQL literals and Default for the SQL DEFAULT keyword.

func (InsertQuery) ValuesFrom added in v0.4.0

func (q InsertQuery) ValuesFrom(row any) InsertQuery

ValuesFrom appends a VALUES row from the current values stored in Column fields on a table model. If Columns was already called, values are read in that column order.

func (InsertQuery) ValuesRows added in v0.4.0

func (q InsertQuery) ValuesRows(rows [][]any) InsertQuery

ValuesRows appends multiple VALUES rows. Plain Go values are rendered as bound arguments; use Literal for inline SQL literals and Default for the SQL DEFAULT keyword.

func (InsertQuery) ValuesRowsFrom added in v0.4.0

func (q InsertQuery) ValuesRowsFrom(rows any) InsertQuery

ValuesRowsFrom appends VALUES rows from the current values stored in Column fields on a slice of table models. If Columns was already called, values are read in that column order.

type Order added in v0.2.0

type Order struct {
	// contains filtered or unexported fields
}

Order represents an ORDER BY item.

func Asc added in v0.2.0

func Asc(v any) Order

Asc returns an ascending ORDER BY item.

func Desc added in v0.2.0

func Desc(v any) Order

Desc returns a descending ORDER BY item.

func (Order) NullsFirst added in v0.2.0

func (o Order) NullsFirst() Order

NullsFirst returns an order item with NULLS FIRST.

func (Order) NullsLast added in v0.2.0

func (o Order) NullsLast() Order

NullsLast returns an order item with NULLS LAST.

func (Order) Render added in v0.2.0

func (o Order) Render(w *strings.Builder, d dialect.Renderer)

Render writes the SQL representation of the order item.

func (Order) Tables added in v0.2.0

func (o Order) Tables() core.TablesSet

Tables returns table references used by the order item.

type Predicate added in v0.2.0

type Predicate struct {
	// contains filtered or unexported fields
}

Predicate represents a SQL boolean predicate.

func And added in v0.1.0

func And(ps ...core.Predicater) Predicate

And combines predicates with SQL AND.

func Or added in v0.1.0

func Or(ps ...core.Predicater) Predicate

Or combines predicates with SQL OR.

func (Predicate) Precedence added in v0.2.0

func (p Predicate) Precedence() int

Precedence returns the predicate precedence used for parenthesizing SQL.

func (Predicate) Predicate added in v0.2.0

func (p Predicate) Predicate()

Predicate marks the value as a predicate.

func (Predicate) Render added in v0.2.0

func (p Predicate) Render(w *strings.Builder, d dialect.Renderer)

Render writes the SQL representation of the predicate.

func (Predicate) Tables added in v0.2.0

func (p Predicate) Tables() core.TablesSet

Tables returns table references used by the predicate.

type SelectQuery added in v0.1.0

type SelectQuery struct {
	// contains filtered or unexported fields
}

SelectQuery represents a SELECT statement under construction.

func Select added in v0.1.0

func Select(cols ...core.Selecter) SelectQuery

Select starts a SELECT query for the given expressions.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[exampleUser]()

	sql, args := q.Select(users.ID, users.UserName).
		Where(users.Age.Ge(18), users.UserName.Eq("Alice")).
		OrderBy(users.ID.Asc()).
		Limit(10).
		MustRender(dialect.PostgreSQL{})

	fmt.Println(sql)
	fmt.Println(args)

}
Output:
SELECT "users"."id", "users"."user_name"
FROM "users"
WHERE "users"."age" >= $1 AND "users"."user_name" = $2
ORDER BY "users"."id" ASC
LIMIT 10
[18 Alice]

func (SelectQuery) CTE added in v0.2.0

CTE wraps the query as a common table expression.

func (SelectQuery) CTEs added in v0.2.0

func (q SelectQuery) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the query.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

func main() {
	cte1 := q.Select(q.Literal(1)).CTE("cte1").WithColumns("c1")
	query := q.Select(cte1.Column("c1"))

	sql, _ := query.MustRender(dialect.PostgreSQL{})
	fmt.Println(sql)
}
Output:
WITH "cte1" ("c1") AS (
    SELECT 1
)
SELECT "cte1"."c1"
FROM "cte1"
Example (Complex_recursive_query)
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type Node struct {
	q.Table `table:"node"`

	ID       q.Column[int]
	ParentID q.Column[int]
	Value    q.Column[int]
}

type NodeStatus struct {
	q.Table `table:"node_status"`

	NodeID q.Column[int]
	Status q.Column[string]
}

func main() {
	NodeTable := q.MustNewTable[Node]()
	NodeStatusTable := q.MustNewTable[NodeStatus]()

	level := q.Literal(1).As("level")
	base := q.
		Select(NodeTable.ID, NodeTable.ParentID, level).
		Join(NodeStatusTable, NodeTable.ID.Eq(NodeStatusTable.NodeID)).
		Where(NodeStatusTable.Status.Eq(q.Literal("active"))).
		CTE("nodes").
		Recursive().
		WithColumns("id", "parent_id", "level")

	rlevel := base.Column("level").Add(q.Literal(1)).As("level")

	recursive := q.
		Select(NodeTable.ID, NodeTable.ParentID, rlevel).
		Join(base, NodeTable.ParentID.Eq(base.Column("id")))

	cte := base.UnionAll(recursive.Limit(1)).CTE("nodes")

	query := q.
		Select(cte.Column("id"), cte.Column("parent_id"), cte.Column("level")).
		OrderBy(cte.Column("level"))

	sql, _ := query.MustRender(dialect.PostgreSQL{})
	fmt.Println(sql)
}
Output:
WITH RECURSIVE "nodes" AS (
    SELECT "node"."id", "node"."parent_id", 1 AS "level"
    FROM "node"
    JOIN "node_status" ON "node"."id" = "node_status"."node_id"
    WHERE "node_status"."status" = 'active'
    UNION ALL
    (SELECT "node"."id", "node"."parent_id", "nodes"."level" + 1 AS "level"
    FROM "node"
    JOIN "nodes" ON "node"."parent_id" = "nodes"."id"
    LIMIT 1)
)
SELECT "nodes"."id", "nodes"."parent_id", "nodes"."level"
FROM "nodes"
ORDER BY "nodes"."level"

func (SelectQuery) CrossJoin added in v0.2.0

func (q SelectQuery) CrossJoin(table TableConfigProvider) SelectQuery

CrossJoin adds a CROSS JOIN to the query.

func (SelectQuery) FullJoin added in v0.2.0

func (q SelectQuery) FullJoin(table TableConfigProvider, predicates ...core.Predicater) SelectQuery

FullJoin adds a FULL JOIN to the query.

func (SelectQuery) GroupBy added in v0.2.0

func (q SelectQuery) GroupBy(cols ...core.Selecter) SelectQuery

GroupBy appends expressions to the GROUP BY clause.

func (SelectQuery) Having added in v0.2.0

func (q SelectQuery) Having(predicates ...core.Predicater) SelectQuery

Having appends predicates to the HAVING clause.

func (SelectQuery) Join added in v0.2.0

func (q SelectQuery) Join(table TableConfigProvider, predicates ...core.Predicater) SelectQuery

Join adds an INNER JOIN to the query.

func (SelectQuery) LeftJoin added in v0.2.0

func (q SelectQuery) LeftJoin(table TableConfigProvider, predicates ...core.Predicater) SelectQuery

LeftJoin adds a LEFT JOIN to the query.

func (SelectQuery) Limit added in v0.1.0

func (q SelectQuery) Limit(l int) SelectQuery

Limit sets a LIMIT clause on the query.

func (SelectQuery) MustRender added in v0.5.0

func (q SelectQuery) MustRender(d dialect.Renderer) (sql string, args []any)

MustRender is like Render but panics if the query is invalid.

func (SelectQuery) Offset added in v0.1.0

func (q SelectQuery) Offset(o int) SelectQuery

Offset sets an OFFSET clause on the query.

func (SelectQuery) OrderBy added in v0.2.0

func (q SelectQuery) OrderBy(items ...core.Selecter) SelectQuery

OrderBy appends expressions to the ORDER BY clause.

func (SelectQuery) RecursiveCTE added in v0.2.0

func (q SelectQuery) RecursiveCTE(name string) CommonTableExpression

RecursiveCTE wraps the query as a recursive common table expression.

func (SelectQuery) Render added in v0.1.0

func (q SelectQuery) Render(d dialect.Renderer) (sql string, args []any, err error)

Render renders the query and returns SQL, bound arguments and an error if the query is invalid.

func (SelectQuery) RenderQueryExpression added in v0.2.0

func (q SelectQuery) RenderQueryExpression(w *strings.Builder, d dialect.Renderer)

RenderQueryExpression writes the SELECT query body.

func (SelectQuery) RenderSetOperand added in v0.2.0

func (q SelectQuery) RenderSetOperand(w *strings.Builder, d dialect.Renderer)

RenderSetOperand writes the query as an operand in a set operation.

func (SelectQuery) RenderStatement added in v0.4.0

func (q SelectQuery) RenderStatement(w *strings.Builder, d dialect.Renderer)

RenderStatement writes the SELECT query body.

func (SelectQuery) RightJoin added in v0.2.0

func (q SelectQuery) RightJoin(table TableConfigProvider, predicates ...core.Predicater) SelectQuery

RightJoin adds a RIGHT JOIN to the query.

func (SelectQuery) Union added in v0.2.0

Union combines this query with another query using UNION.

func (SelectQuery) UnionAll added in v0.2.0

func (q SelectQuery) UnionAll(other core.QueryExpression) CompoundQuery

UnionAll combines this query with another query using UNION ALL.

func (SelectQuery) Where added in v0.1.0

func (q SelectQuery) Where(predicates ...core.Predicater) SelectQuery

Where appends predicates to the query's WHERE clause.

type Table added in v0.4.0

type Table struct {
	// contains filtered or unexported fields
}

Table can be embedded into table models to provide table configuration.

func (Table) TableConfig added in v0.4.0

func (t Table) TableConfig() TableConfig

TableConfig returns the embedded table configuration.

type TableConfig

type TableConfig struct {
	// Name is the SQL table name.
	Name string
}

TableConfig describes a SQL table.

type TableConfigProvider

type TableConfigProvider interface {
	TableConfig() TableConfig
}

TableConfigProvider is implemented by table model structs with a TableConfig method.

type TableRefProvider added in v0.2.0

type TableRefProvider interface {
	TableRef() core.TableRef
}

TableRefProvider is implemented by values that expose an explicit table reference.

type TableRefer added in v0.3.0

type TableRefer interface {
	TableRef() core.TableRef
}

TableRefer identifies values that carry table reference information.

type UpdateQuery added in v0.4.0

type UpdateQuery struct {
	// contains filtered or unexported fields
}

UpdateQuery represents an UPDATE statement under construction.

func Update added in v0.4.0

func Update(table TableConfigProvider) UpdateQuery

Update starts an UPDATE query for the given table.

Example
package main

import (
	"fmt"

	q "github.com/SennovE/qrafter"
	"github.com/SennovE/qrafter/dialect"
)

type exampleUser struct {
	q.Table `table:"users"`

	ID       q.Column[int] `db:"id"`
	UserName q.Column[string]
	Age      q.Column[int]
}

func main() {
	users := q.MustNewTable[exampleUser]()

	sql, args := q.Update(users).
		Set(users.UserName, "Alice").
		Where(users.ID.Eq(1)).
		Returning(users.ID, users.UserName).
		MustRender(dialect.PostgreSQL{})

	fmt.Println(sql)
	fmt.Println(args)

}
Output:
UPDATE "users"
SET "user_name" = $1
WHERE "users"."id" = $2
RETURNING "users"."id", "users"."user_name"
[Alice 1]

func (UpdateQuery) CTEs added in v0.4.0

func (q UpdateQuery) CTEs() []*core.CTERef

CTEs returns common table expressions referenced by the UPDATE query.

func (UpdateQuery) From added in v0.4.0

func (q UpdateQuery) From(tables ...TableConfigProvider) UpdateQuery

From appends tables to the UPDATE FROM clause.

func (UpdateQuery) MustRender added in v0.5.0

func (q UpdateQuery) MustRender(d dialect.Renderer) (sql string, args []any)

MustRender is like Render but panics if the query is invalid.

func (UpdateQuery) Render added in v0.4.0

func (q UpdateQuery) Render(d dialect.Renderer) (sql string, args []any, err error)

Render renders the query and returns SQL, bound arguments and an error if the query is invalid.

func (UpdateQuery) RenderStatement added in v0.4.0

func (q UpdateQuery) RenderStatement(w *strings.Builder, d dialect.Renderer)

RenderStatement writes the UPDATE query body.

func (UpdateQuery) Returning added in v0.4.0

func (q UpdateQuery) Returning(items ...core.Selecter) UpdateQuery

Returning appends expressions to a RETURNING clause.

func (UpdateQuery) Set added in v0.4.0

func (q UpdateQuery) Set(column ColumnRef, value any) UpdateQuery

Set appends a column assignment to the UPDATE SET clause. Plain Go values are rendered as bound arguments; use Literal for inline SQL literals and Default for the SQL DEFAULT keyword.

func (UpdateQuery) SetFrom added in v0.4.0

func (q UpdateQuery) SetFrom(row any) UpdateQuery

SetFrom appends assignments from the current values stored in Column fields on a table model.

func (UpdateQuery) Where added in v0.4.0

func (q UpdateQuery) Where(predicates ...core.Predicater) UpdateQuery

Where appends predicates to the UPDATE WHERE clause.

type WindowFrame added in v0.2.0

type WindowFrame struct {
	// contains filtered or unexported fields
}

WindowFrame represents a SQL window frame clause.

func (WindowFrame) Render added in v0.2.0

func (f WindowFrame) Render(w *strings.Builder, d dialect.Renderer)

Render writes the SQL window frame.

type WindowFrameBound added in v0.2.0

type WindowFrameBound struct {
	// contains filtered or unexported fields
}

WindowFrameBound represents a SQL window frame bound.

func CurrentRow added in v0.2.0

func CurrentRow() WindowFrameBound

CurrentRow returns a CURRENT ROW frame bound.

func Following added in v0.2.0

func Following(v any) WindowFrameBound

Following returns a FOLLOWING frame bound.

func FrameBound added in v0.2.0

func FrameBound(value string) WindowFrameBound

FrameBound returns a custom frame bound.

func Preceding added in v0.2.0

func Preceding(v any) WindowFrameBound

Preceding returns a PRECEDING frame bound.

func UnboundedFollowing added in v0.2.0

func UnboundedFollowing() WindowFrameBound

UnboundedFollowing returns an UNBOUNDED FOLLOWING frame bound.

func UnboundedPreceding added in v0.2.0

func UnboundedPreceding() WindowFrameBound

UnboundedPreceding returns an UNBOUNDED PRECEDING frame bound.

func (WindowFrameBound) Render added in v0.2.0

Render writes the SQL window frame bound.

type WindowFrameMode added in v0.2.0

type WindowFrameMode struct {
	// contains filtered or unexported fields
}

WindowFrameMode represents a SQL window frame mode such as ROWS or RANGE.

func Groups added in v0.2.0

func Groups() WindowFrameMode

Groups returns a GROUPS window frame mode.

func Range added in v0.2.0

func Range() WindowFrameMode

Range returns a RANGE window frame mode.

func Rows added in v0.2.0

func Rows() WindowFrameMode

Rows returns a ROWS window frame mode.

func (WindowFrameMode) Between added in v0.2.0

func (m WindowFrameMode) Between(start, end WindowFrameBound) WindowFrame

Between returns a frame with BETWEEN start AND end bounds.

func (WindowFrameMode) Bound added in v0.2.0

Bound returns a frame with a single bound.

func (WindowFrameMode) CurrentRow added in v0.2.0

func (m WindowFrameMode) CurrentRow() WindowFrame

CurrentRow returns a frame bound to CURRENT ROW.

func (WindowFrameMode) Following added in v0.2.0

func (m WindowFrameMode) Following(v any) WindowFrame

Following returns a frame with a FOLLOWING bound.

func (WindowFrameMode) Preceding added in v0.2.0

func (m WindowFrameMode) Preceding(v any) WindowFrame

Preceding returns a frame with a PRECEDING bound.

func (WindowFrameMode) UnboundedPreceding added in v0.2.0

func (m WindowFrameMode) UnboundedPreceding() WindowFrame

UnboundedPreceding returns a frame ending at UNBOUNDED PRECEDING.

type WindowSpec added in v0.2.0

type WindowSpec struct {
	// contains filtered or unexported fields
}

WindowSpec represents a SQL window specification.

func PartitionBy added in v0.2.0

func PartitionBy(cols ...any) WindowSpec

PartitionBy starts a window specification with PARTITION BY expressions.

func Window added in v0.2.0

func Window() WindowSpec

Window starts an empty window specification.

func (WindowSpec) Frame added in v0.2.0

func (s WindowSpec) Frame(frame WindowFrame) WindowSpec

Frame sets the frame clause for the window specification.

func (WindowSpec) OrderBy added in v0.2.0

func (s WindowSpec) OrderBy(items ...any) WindowSpec

OrderBy appends ORDER BY expressions to the window specification.

func (WindowSpec) PartitionBy added in v0.2.0

func (s WindowSpec) PartitionBy(cols ...any) WindowSpec

PartitionBy appends PARTITION BY expressions to the window specification.

func (WindowSpec) Render added in v0.2.0

func (s WindowSpec) Render(w *strings.Builder, d dialect.Renderer)

Render writes the SQL window specification.

func (WindowSpec) Tables added in v0.2.0

func (s WindowSpec) Tables() core.TablesSet

Tables returns table references used by the window specification.

Directories

Path Synopsis
Package ddl builds SQL data definition statements.
Package ddl builds SQL data definition statements.
Package dialect contains SQL rendering dialects for qrafter queries.
Package dialect contains SQL rendering dialects for qrafter queries.
internal

Jump to

Keyboard shortcuts

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