Skip to content

v0.3.0 — Query Builder

Choose a tag to compare

@Grandbusta Grandbusta released this 13 Jul 12:01
· 4 commits to main since this release
c4343dc

🎉 Jone v0.3.0

The query builder is here! Jone now goes beyond migrations with a fluent, fully parameterized query builder for INSERT, SELECT, UPDATE, and DELETE — plus transactions and PostgreSQL RETURNING support.

✨ What's New

Query Builder

  • jone init now generates a ready-to-use DB instance in your jonefile.go — the connection is lazy and opens automatically on your first query
  • INSERT accepts a map[string]any, []map[string]any, a struct, or a slice of structs (using db tags with snake_case fallback)
  • Multi-row inserts generate a single INSERT INTO ... VALUES (...), (...) statement
  • Conflict handling with OnConflict().Ignore() — no target, column targets, or partial-index expressions (ON CONFLICT DO NOTHING on PostgreSQL, INSERT IGNORE on MySQL)
  • SELECT with column selection, ordering, pagination, and First() for fetching a single row as a map[string]any
  • UPDATE and DELETE with parameterized SET values and WHERE conditions
  • ToSQL() on every builder to inspect the generated SQL and args without executing

Parameterized WHERE Clauses

  • Conditions with bound values — never string interpolation: Where("age", ">", 18), Where("email", v)
  • Full family: OrWhere, WhereIn / WhereNotIn, WhereNull / WhereNotNull, and WhereRaw as the raw-SQL escape hatch (? placeholders are rebound to $n on PostgreSQL automatically)
  • Condition groups: pass a func to Where/OrWhere for parenthesized groups, nestable to any depth:
db.Select("*").From("users").
    Where("active", true).
    Where(func(g *jone.WhereGroup) {
        g.Where("role", "admin").OrWhere("age", ">", 65)
    }).
    Exec()
// WHERE "active" = $1 AND ("role" = $2 OR "age" > $3)
  • Injection-safe OrderBy("created_at", "desc") — columns are quoted and directions validated; OrderByRaw for expressions

RETURNING Support (PostgreSQL)

  • ExecReturning("id", ...) on Insert, Update, and Delete returns the affected rows as []map[string]any
  • Solves LastInsertId() being unsupported by the PostgreSQL driver — get your generated IDs back directly
  • On MySQL, keep using Exec() with result.LastInsertId()

Transactions

  • db.Transaction(func(tx *jone.Schema) error { ... }) — automatically commits on nil return, rolls back on error
  • db.Begin() returns a TxSchema for manual Commit() / Rollback() control
  • All query methods work inside transactions

Raw Expressions

  • jone.Raw("gen_random_uuid()") inlines any SQL expression where a value is expected
  • jone.Fn.Now() shorthand for CURRENT_TIMESTAMP

⚠️ Breaking Changes

  • jone.NewSchema() is renamed to jone.New() — update your jonefile.go (or re-run jone init in a fresh project to see the new template)

📦 Installation

go install github.com/Grandbusta/jone/cmd/jone@v0.3.0