44[ ![ Go CI] ( https://github.com/SennovE/qrafter/actions/workflows/go.yml/badge.svg?branch=main )] ( https://github.com/SennovE/qrafter/actions/workflows/go.yml )
55[ ![ Go Report Card] ( https://goreportcard.com/badge/github.com/SennovE/qrafter )] ( https://goreportcard.com/report/github.com/SennovE/qrafter )
66
7- ** qrafter is a fluent, type-safe SQL query builder for Go — no ORM, no codegen, just typed SQL-shaped Go.**
7+ qrafter is a fluent, type-safe SQL toolkit for Go. It gives you typed query
8+ composition, DDL builders, schema introspection, and generated Go migrations
9+ without becoming an ORM.
810
9- qrafter helps you build parameterized SQL from typed Go table structs.
10- You define tables once, compose queries from typed columns, and render SQL plus
11- driver arguments for ` database/sql ` , ` sqlx ` , and similar packages.
12-
13- It is designed for Go developers who want a Go-style way to build explicit SQL: keep queries readable and under control, while avoiding fragile hand-written column names, placeholders, and query fragments.
14-
15- ## Why qrafter?
16-
17- Use qrafter when you want:
18-
19- - Typed table and column references with ` qrafter.Column[T] `
20- - SQL that still looks and feels like SQL
21- - Parameterized queries instead of interpolated user values
22- - Dialect-aware identifier quoting and placeholders
23- - Compatibility with your existing database driver and connection pool
24- - A lightweight query builder instead of a full ORM
25- - No code generation step in your build workflow
11+ Use qrafter when you want explicit SQL, typed table/column references,
12+ database/sql compatibility, and migration files you can read and edit.
2613
2714## Install
2815
@@ -81,80 +68,88 @@ LIMIT 10
8168[18 Alice]
8269```
8370
84- ## Larger examples
71+ ## Migrations
8572
86- More application-shaped examples live in [ examples] ( examples ) :
73+ The migration tool lives in ` cmd/qrafter-migrations ` . It creates a Go config
74+ file, compares the configured schema with the live database, generates Go
75+ migration files, registers them, and applies or reverts them.
8776
88- * [ database_sql] ( examples/database_sql ) shows repository-style code with
89- ` database/sql ` , context-aware execution, and typed query rendering.
90- * [ reporting] ( examples/reporting ) builds a larger analytical query with joins,
91- grouping, a CTE, and a window function.
92- * [ schema] ( examples/schema ) renders DDL for tables, constraints, indexes, and
93- table alterations.
77+ Show CLI help:
9478
95- ## How it works
79+ ``` sh
80+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest help
81+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest help revision
82+ ```
9683
97- A qrafter table is a Go struct with typed column fields :
84+ Create ` ./migrations/qrafter_config.go ` :
9885
99- ``` go
100- type User struct {
101- q.Table ` table:"users"`
102-
103- ID q.Column [int ] ` db:"id"`
104- UserName q.Column [string ]
105- Age q.Column [int ]
106- }
86+ ``` sh
87+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest init \
88+ --dir ./migrations \
89+ --driver-import github.com/lib/pq \
90+ --driver postgres \
91+ --dialect postgres \
92+ --dsn " postgres://app_user:app_password@localhost:5432/app_db?sslmode=disable"
10793```
10894
109- ` q.MustNewTable[User]() ` binds the struct fields to SQL table and column names.
110- Queries are then composed from those typed columns and rendered for a selected
111- SQL dialect.
95+ The generated config is regular Go code. Add your table configs to
96+ ` desiredSchema ` :
97+
98+ ``` go
99+ package migrations
100+
101+ import (
102+ " github.com/SennovE/qrafter/dialect"
103+ qmig " github.com/SennovE/qrafter/migrations"
104+ _ " github.com/lib/pq"
105+ )
112106
113- Field names are converted into column names automatically, or you can override
114- them with ` db ` tags.
107+ var MigrationConfig = qmig.MigrationToolConfig {
108+ DriverName : " postgres" ,
109+ DataSourceName : " postgres://app_user:app_password@localhost:5432/app_db?sslmode=disable" ,
110+ Introspector : qmig.NewPostgreSQL (qmig.WithSchemas (" public" )),
111+ Dialect : dialect.PostgreSQL {},
112+ Desired : desiredSchema,
113+ VersionTable : qmig.DefaultMigrationVersionTable ,
114+ }
115115
116- ## When to use it
116+ var Registry = []qmig.Migration {
117+ }
117118
118- qrafter is useful when you want typed query composition while still keeping
119- control over the generated SQL.
119+ func desiredSchema (d dialect .Renderer ) qmig .Schema {
120+ var schema qmig.Schema
121+ qmig.RegisterTable [User](&schema, d)
122+ return schema
123+ }
124+ ```
120125
121- Good fits :
126+ Generate a migration from the live database diff :
122127
123- * services that already use ` database/sql ` or ` sqlx `
124- * projects that prefer explicit SQL over ORM abstractions
125- * codebases where query fragments need to be composed safely
126- * applications that want typed table and column references without codegen
128+ ``` sh
129+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest revision \
130+ --dir ./migrations \
131+ --comment create_users
132+ ```
127133
128- Less ideal fits:
134+ This creates a timestamped Go file and appends it to ` Registry ` in
135+ ` qrafter_config.go ` . Generated migrations return ` ddl.Statements ` , so you can
136+ edit them and add custom statements such as ` qddl.RawSQL("CREATE EXTENSION ...") `
137+ when needed.
129138
130- * projects that want a full ORM
131- * applications that expect automatic relationship loading
132- * teams that prefer writing raw SQL files and generating Go code from them
133- * projects that need schema migrations as part of the same tool
139+ Apply or revert registered migrations:
134140
135- ## Features
141+ ``` sh
142+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest up --dir ./migrations --to head
143+ go run github.com/SennovE/qrafter/cmd/qrafter-migrations@latest down --dir ./migrations --to base
144+ ```
136145
137- * Typed table structs with ` qrafter.Column[T] `
138- * Table configuration via embedded ` qrafter.Table ` or ` TableConfig() `
139- * Automatic column binding from field names or ` db ` tags
140- * Custom field-to-column mapping through ` qrafter.NameMapper `
141- * Dialect-aware identifier quoting and placeholders
142- * Human-readable multiline SQL rendering
143- * Parameterized ` SELECT ` , joins, grouping, ordering, limits, and offsets
144- * Parameterized ` INSERT ` with ` VALUES ` , ` DEFAULT VALUES ` , ` INSERT ... SELECT ` , and ` RETURNING `
145- * Parameterized ` UPDATE ` with ` SET ` , ` FROM ` , ` WHERE ` , CTEs, and ` RETURNING `
146- * Parameterized ` DELETE ` with ` WHERE ` , ` USING ` , CTEs, and ` RETURNING `
147- * CTEs and recursive CTEs
148- * Compound queries such as ` UNION ` and ` UNION ALL `
149- * Aggregates and window functions
150- * DDL builders for tables, columns, constraints, and indexes
151- * Centralized SQL compiler with dialect override hooks for database-specific syntax
152- * ` database/sql ` and ` sqlx ` -friendly scanning helpers
146+ The apply command stores the current version in
147+ ` qrafter_schema_version ` by default. Override it in config with
148+ ` VersionTable ` or from CLI with ` --version-table ` .
153149
154- ## DDL
150+ ## DDL Builders
155151
156- Schema statements live in the separate ` ddl ` package so the root package can
157- stay focused on query building:
152+ Schema statements live in the ` ddl ` package:
158153
159154``` go
160155sql , err := ddl.CreateTable (" users" ).
@@ -166,87 +161,39 @@ sql, err := ddl.CreateTable("users").
166161 Render (dialect.PostgreSQL {})
167162```
168163
169- DDL rendering returns an error when a dialect cannot safely render a requested
170- feature, such as SQLite column type changes or MySQL partial indexes.
171-
172- Constraints and indexes are built explicitly from table and column names:
173-
174- ``` go
175- sql , err := ddl.Statements {
176- ddl.CreateTable (" users" ).
177- Columns (
178- ddl.Column (" id" , ddl.BigSerial ()).PrimaryKey (),
179- ddl.Column (" org_id" , ddl.BigInt ()).NotNull (),
180- ddl.Column (" email" , ddl.VarChar (320 )).NotNull (),
181- ).
182- Constraints (
183- ddl.Unique (" email" ).Named (" users_email_key" ),
184- ddl.ForeignKey (" org_id" ).
185- References (" orgs" , " id" ).
186- OnDelete (ddl.Cascade ),
187- ),
188- ddl.CreateIndex (" users_email_idx" ).
189- IfNotExists ().
190- OnCols (" users" , " email" ),
191- }.Render (dialect.PostgreSQL {})
192- ```
164+ DDL rendering is dialect-aware and returns an error when a dialect cannot safely
165+ render a requested feature.
193166
194167## Dialects
195168
196169qrafter currently includes:
197170
198- * ` dialect.BaseDialect ` for ANSI-style double-quoted identifiers and ` ? ` placeholders
199- * ` dialect.PostgreSQL ` for PostgreSQL-style ` $1 ` , ` $2 ` , ... placeholders
200- * ` dialect.MySQL ` for backtick-quoted identifiers, MySQL ` LIMIT ` /` OFFSET ` ,
201- empty-row inserts, multi-table ` UPDATE ` /` DELETE ` , and NULL ordering emulation
202- * ` dialect.SQLite ` for SQLite literals, ` LIMIT ` /` OFFSET ` , and fail-fast
203- handling for unsupported ` DELETE USING `
204- * ` dialect.Oracle ` for Oracle placeholders, boolean literals,
205- ` OFFSET ` /` FETCH ` , and Oracle-specific DDL overrides
206- * ` dialect.SQLServer ` for bracket-quoted identifiers, ` @p1 ` placeholders,
207- ` OFFSET ` /` FETCH ` , NULL ordering emulation, and SQL Server DDL overrides
208-
209- Rendering is intentionally centralized. Query and DDL builders store statement
210- state; the compiler renders statements, expressions, clauses, and DDL nodes; a
211- dialect supplies primitive rules such as identifier quoting, literals,
212- placeholders, and ` LIMIT ` /` OFFSET ` , and can override specific compiler nodes
213- with ` CompileNode ` .
214-
215- New dialects can start with the primitive methods and then override focused
216- nodes for features such as ` RETURNING ` , ` UPDATE ` sources, ` DELETE ` sources,
217- joins, default inserts, NULL ordering, partial indexes, and dialect-specific
218- ` ALTER TABLE ` forms.
219-
220- New dialects can be added by implementing ` dialect.Renderer ` .
221-
222- ## Comparison
223-
224- | Approach | Good when | Tradeoff |
225- | ------------------- | ----------------------------------------------------- | ------------------------------------------------------------------- |
226- | Raw ` database/sql ` | You want full control over every query | SQL strings, placeholders, and column names are maintained manually |
227- | SQL code generation | You want generated Go code from SQL files | Adds a generation step and a SQL-first workflow |
228- | ORM | You want high-level model and relationship management | SQL can become less explicit and harder to control |
229- | qrafter | You want typed SQL-shaped Go without ORM or codegen | It is a lightweight query builder, not a full database framework |
230-
231- ## Project status
232171
233- qrafter is pre-v1. The API may still change while the package evolves.
172+ dialect | DML | DDL | migrations
173+ ----------- |:---:|:---:|:----------:
174+ BaseDialect | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | -
175+ PostgreSQL | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul >
176+ MySQL | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ ] </li ></ul >
177+ SQLite | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ ] </li ></ul >
178+ Oracle | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ ] </li ></ul >
179+ SQLServer | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ x] </li ></ul > | <ul ><li >- [ ] </li ></ul >
234180
235- Feedback is especially welcome around:
181+ ## Examples
236182
237- * API naming
238- * query composition ergonomics
239- * dialect support
240- * real-world usage with ` database/sql ` and ` sqlx `
183+ More application-shaped examples live in [ examples] ( examples ) :
241184
242- ## Contributing
185+ - [ database_sql] ( examples/database_sql ) shows repository-style code with
186+ ` database/sql ` .
187+ - [ reporting] ( examples/reporting ) builds a larger analytical query with joins,
188+ grouping, a CTE, and a window function.
189+ - [ schema] ( examples/schema ) renders DDL for tables, constraints, indexes, and
190+ table alterations.
191+ - [ migrations] ( examples/migrations ) is a standalone module with Docker Compose
192+ that generates, applies, and reverts qrafter migrations against PostgreSQL.
243193
244- Contributions are welcome. See [ CONTRIBUTING.md] ( CONTRIBUTING.md ) for the local
245- development workflow and pull request guidelines.
194+ ## Project Status
246195
247- Good first areas to explore:
196+ qrafter is pre-v1. The API may still change while the package evolves.
248197
249- * Add examples for common query patterns
250- * Improve dialect coverage
251- * Expand integration tests
252- * Polish package documentation on pkg.go.dev
198+ Contributions are welcome. See [ CONTRIBUTING.md] ( CONTRIBUTING.md ) for the local
199+ development workflow and pull request guidelines.
0 commit comments