go-lightning is a lightweight, high-performance database interaction library for Go. It is designed to be slim, fast, and easy to use, especially when working with projections and Data Transfer Objects (DTOs).
The project is currently used in a production environment.
- Unified API: The
litpackage provides a single API for both PostgreSQL and MySQL, with driver-specific optimizations handled internally. - Lightweight Projections: The biggest advantage of
go-lightningis its ability to load DTOs and projections with minimal effort. Regardless of your table structure, mapping a query result to a Go struct is straightforward and clean. - MySQL and PostgreSQL Support: Register your models with the appropriate driver and the library handles query generation and driver-specific optimizations.
- Generic CRUD Operations: Automatic generation of
INSERTandUPDATEqueries for registered types. - Works with DB and Tx: All operations accept both
*sql.DBand*sql.Txvia theExecutorinterface. - Minimal Dependencies: Keeps your project slim and focused.
Documentation is available at https://tracewayapp.github.io/go-lightning
- ID Column Requirement: For automatic
InsertandUpdateoperations, the library requires your tables to have anidcolumn. It does not support tables without a primaryidfield for these specific automatic operations.
go get github.com/tracewayapp/go-lightning/litEvery model you intend to use with generic functions must be registered with a specific driver.
import "github.com/tracewayapp/go-lightning/lit"
type User struct {
Id int
FirstName string
LastName string
Email string
}
func init() {
// Register for PostgreSQL
lit.RegisterModel[User](lit.PostgreSQL)
// OR Register for MySQL
lit.RegisterModel[User](lit.MySQL)
}Placeholder Syntax: PostgreSQL uses $1, $2, $3... placeholders while MySQL uses ? placeholders. The examples below use PostgreSQL syntax.
import (
"github.com/tracewayapp/go-lightning/lit"
_ "github.com/jackc/pgx/v5/stdlib"
)
func example(db *sql.DB) {
// Insert - returns auto-generated ID
id, _ := lit.Insert(db, &User{FirstName: "Jane", LastName: "Smith"})
// Select Single
user, _ := lit.SelectSingle[User](db, "SELECT * FROM users WHERE id = $1", id)
// Select Multiple
users, _ := lit.Select[User](db, "SELECT * FROM users WHERE last_name = $1", "Smith")
// Update
user.Email = "jane@example.com"
_ = lit.Update(db, user, "id = $1", user.Id)
// Delete
_ = lit.Delete(db, "DELETE FROM users WHERE id = $1", user.Id)
}All operations work with both *sql.DB and *sql.Tx:
func exampleWithTx(db *sql.DB) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
// All operations accept tx
id, err := lit.Insert(tx, &User{FirstName: "John"})
if err != nil {
return err
}
user, err := lit.SelectSingle[User](tx, "SELECT * FROM users WHERE id = $1", id)
if err != nil {
return err
}
return tx.Commit()
}For models with string ID fields, use UUID-specific insert functions:
type Product struct {
Id string
Name string
Price int
}
func init() {
lit.RegisterModel[Product](lit.PostgreSQL)
}
func example(db *sql.DB) {
// Auto-generate UUID
uuid, _ := lit.InsertUuid(db, &Product{Name: "Widget", Price: 100})
// Use existing UUID
product := &Product{Id: "my-custom-uuid", Name: "Gadget", Price: 200}
_ = lit.InsertExistingUuid(db, product)
}// JoinForIn - for integer IN clauses
ids := []int{1, 2, 3}
query := fmt.Sprintf("SELECT * FROM users WHERE id IN (%s)", lit.JoinForIn(ids))
// JoinStringForIn - generates driver-appropriate placeholders
// PostgreSQL: $1,$2,$3 (with offset support)
// MySQL: ?,?,?
names := []string{"a", "b", "c"}
placeholders := lit.JoinStringForIn[User](0, names)
// Or specify driver explicitly
placeholders := lit.JoinStringForInWithDriver(lit.PostgreSQL, 0, 3) // "$1,$2,$3"
placeholders := lit.JoinStringForInWithDriver(lit.MySQL, 0, 3) // "?,?,?"By default, go-lightning converts Go struct field names from CamelCase to snake_case for database column names:
| Struct Field | Database Column |
|---|---|
Id |
id |
FirstName |
first_name |
LastName |
last_name |
Email |
email |
You can override the default naming by using the lit struct tag:
type User struct {
Id int `lit:"id"`
FirstName string `lit:"first_name"`
LastName string `lit:"surname"` // Maps to "surname" instead of "last_name"
Email string `lit:"email_address"` // Maps to "email_address" instead of "email"
}The lit tag is used for:
- INSERT queries: Column names in the generated INSERT statement
- UPDATE queries: Column names in the generated UPDATE statement
- SELECT queries: Mapping database columns back to struct fields
You can use lit tags on only some fields. Fields without tags use the default snake_case conversion:
type User struct {
Id int // Uses default: "id"
FirstName string `lit:"given_name"` // Uses tag: "given_name"
LastName string // Uses default: "last_name"
PhoneNumber string `lit:"phone"` // Uses tag: "phone"
}For more control over naming conventions, you can implement the DbNamingStrategy interface and use RegisterModelWithNaming:
type MyNamingStrategy struct{}
func (m MyNamingStrategy) GetTableNameFromStructName(name string) string {
return strings.ToLower(name) // e.g., "User" -> "user"
}
func (m MyNamingStrategy) GetColumnNameFromStructName(name string) string {
return strings.ToLower(name) // e.g., "FirstName" -> "firstname"
}
func init() {
lit.RegisterModelWithNaming[User](lit.PostgreSQL, MyNamingStrategy{})
}Note: The lit tag takes precedence over any naming strategy.
We welcome all contributions to the go-lightning project. You can open issues or PR and we will review and promptly merge them.
- Named query parameters
- Add a project homepage
- Add support for composite primary keys
-
Escaping SQL keywords for field names and table names -
Add support for ClickHouse - we're not doing this as clickhouse has a driver that is basically already doing this -
Add more examples - the usercrud example is mostly complete - we'll add more if we get a git issue filed to do so -
Add project docs -
Add support for named fieldslit:"column_name"
- Developer Written: All core logic and architectural decisions were made and implemented by an actual developer.
- AI Assisted Testing: AI was utilized to help generate a comprehensive test suite as well as help out with documentation.
MIT
