Repository navigation
FAQ
No. There are no models, relations, lifecycle hooks or migrations. You write queries with a fluent API and get rows back into your own structs.
PostgreSQL, MySQL, MariaDB and SQLite. Tested on PostgreSQL 16, MySQL 8.4, MariaDB 11.4 and SQLite (pure-Go driver). SQL Server is not supported. See Dialect Differences.
Yes. db.Use(dialect) only builds SQL. Use ToSQL() and run the result with any driver you like.
quill is pre-1.0 (v0.2.0). The API changed between 0.1 and 0.2 and may change again before 1.0. Pin the version and read the changelog before you upgrade.
Yes. db.New accepts anything with QueryContext and ExecContext. A db.New(sqlTx, dialect) built on an existing *sql.Tx uses savepoints for nested Transaction calls.
You have a local variable called db that hides the package. Rename the variable to conn.
You created the DB with db.Use, which has no connection. Use db.New(sqlDB, dialect) to run queries.
The statement has no WHERE and no LIMIT. This guard prevents wiping a table by accident. Add a filter. If you really mean every row, call AllRows(). See the WHERE guard.
The select has no source. Call From, FromSub or FromRaw.
T has no TableName() method, or it returns "". quill never guesses a table name. See Typed API.
Every field was omitted. A field tagged omitempty is skipped while it holds its zero value. See the omitempty trap.
Same cause: omitempty skips zero values. Use a pointer field, or Set / SetMap.
The feature does not exist on the chosen dialect (for example Returning on MySQL, lateral joins on SQLite). Check the dialect table for the alternative.
The operator is not in the allow-list. If it came from user input, that is the guard doing its job.
Builders collect errors and return the first one from the terminal call (ToSQL, Get, Exec, ...). Call q.Err() to look earlier.
Strict servers need the grouped column to be selected: conn.Select("user_id").From("posts").GroupBy("user_id").Count(ctx). See Reading Data.
MySQL counts changed rows. Updating a row to the value it already has reports 0. Upserts report 2 per updated row. See Dialect Differences.
WhereIn with an empty slice compiles to 0 = 1 (matches nothing) and WhereNotIn to 1 = 1, so an empty filter list never produces invalid SQL.
PostgreSQL does not allow output aliases in HAVING. Use HavingRaw("sum(total) > ?", 100).
Chunk pages by offset. If your callback changes rows that match the filter, offsets shift. Use ChunkByID.
Chunk needs an ORDER BY. Add OrderBy("id") or use ChunkByID.
On a single-connection pool such as in-memory SQLite, the open cursor holds the only connection. Do not run another query inside the loop. Collect ids first, or use a pool with more connections.
No. Build per request, or Clone() a shared base before each use. See Core Concepts.
It should not. NULL into a plain field leaves the zero value. Use a pointer or sql.Null* if you need to tell NULL apart. See Reading Data.
q.ToSQL() returns the SQL and arguments. q.ToRawSQL() interpolates values for debugging only: never execute or log it in production.
It is safe from SQL injection (it is only bound as an argument) but it is not signed or encrypted and reveals the last key. See Security.
- Check the Cookbook for a similar task.
- Run
go doc github.com/akfaiz/quill/db <Name>for the doc comment. - Search or open an issue: https://github.com/akfaiz/quill/issues. When reporting, include the dialect, quill version, and the output of
ToSQL(). Do not paste real customer data or credentials.
quill wiki · v0.2.0 · Repository · pkg.go.dev · Report an issue · MIT License
Basics
Building queries
Data access
- Writing Data
- Reading Data
- Pagination and Chunking
- Transactions
- Typed API
- Struct Mapping
- Hooks and Options
Reference
Guides