grain

module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0

README

Grain

Grain is a type-safe Object-Relational Mapping (ORM) for Go, built on pgx. It targets PostgreSQL only.

  • Type-safe schema — tables and columns defined once in Go; column binds are checked at startup, not on first SQL error.
  • Snapshot-driven migrations — edit your schema, then grain generate diffs it against the last applied snapshot and writes the SQL for you.
  • Fluent query builder — SELECT/INSERT/UPDATE/DELETE with joins, conditions, grouping and pagination, parameterized everywhere.
  • Transactions — one method that begins, commits and rolls back for you.
  • Reflection-based scanning — rows map into plain structs via db: tags.

Contents

Installation

Add the library and the grain CLI to your project:

go get github.com/etornam45/grain@latest
go install github.com/etornam45/grain/cmd/grain@latest   # CLI -> $(go env GOPATH)/bin/grain

The CLI is a separate binary from the library — you only need it if you manage migrations with grain generate / grain migrate.

A runnable version of everything below lives in examples/basic.

Usage Example
import "github.com/etornam45/grain/schema"

var UserStatus = schema.Enum("user_status", "active", "suspended", "banned")

type usersColumns struct {
	ID, Name, Email, Age, Status *schema.ColumnDef
}

var Users = schema.Table[usersColumns]("users",
	schema.Column("id", schema.UUID()).PrimaryKey().Default("gen_random_uuid()"),
	schema.Column("name", schema.Varchar(255)).NotNull(),
	schema.Column("email", schema.Varchar(255)).NotNull().Unique(),
	schema.Column("age", schema.Int()),
	schema.Column("status", UserStatus).NotNull().Default("active"),
)
Migrations

Generate a migration from your schema code, then apply it:

grain generate -schema path/to/model "create user table"
DATABASE_URL=postgres://user:pass@localhost:5432/app grain migrate up

Command usage

usage:
  grain generate -schema <dir> [name]
  grain migrate up                       (requires DATABASE_URL)
  grain migrate down                     (requires DATABASE_URL)
  grain migrate status                   (requires DATABASE_URL)
Querying

These snippets assume a table defined as in the Usage example, plus ctx, conn, tx and newID in scope. query is github.com/etornam45/grain/query and db is github.com/etornam45/grain/db.

  1. Inserting
var newID string
err = query.Insert(schema.Users).
	Values(map[string]any{
		"name":   "Ama",
		"email":  "ama@example.com",
		"status": "active",
	}).
	Returning(schema.Users.Cols.ID.String()).
	Scan(ctx, conn, &newID)
  1. Selecting
type User struct {
	ID     string `db:"users.id"`
	Name   string `db:"users.name"`
	Email  string `db:"users.email"`
	Status string `db:"users.status"`
}

users, err := query.Select[User](schema.Users.Cols.ID, schema.Users.Cols.Name, schema.Users.Cols.Email, schema.Users.Cols.Status).
	From(schema.Users).
	Where(query.Eq(schema.Users.Cols.Status, "active")).
	OrderBy([]string{schema.Users.Cols.Name.Str()}, query.Asc).
	Limit(10).
	All(ctx, conn)
  1. Joins
rows, err := query.Select[UserOrderRow](schema.Users.Cols.Name, schema.Orders.Cols.Total).
	From(schema.Users).
	InnerJoin(schema.Orders, query.Eq(schema.Users.Cols.ID, schema.Orders.Cols.UserID)).
	Where(query.Gt(schema.Orders.Cols.Total, 100)).
	All(ctx, conn)
  1. Deleting
_, err = query.Delete(schema.Users).Where(query.Eq(schema.Users.Cols.ID, newID)).Run(ctx, tx)
  1. Transactions
err = conn.Transaction(ctx, func(tx *db.Tx) error {
	_, err := query.Delete(schema.Orders)
		.Where(query.Eq(schema.Orders.Cols.UserID, newID))
		.Run(ctx, tx)
	if err != nil {
		return err
	}
	_, err = query.Delete(schema.Users)
		.Where(query.Eq(schema.Users.Cols.ID, newID))
		.Run(ctx, tx)
	return err
})
Documentation

Full library reference and tutorials live in docs/:

  • Schema — tables, columns, types, enums, foreign keys, indexes
  • Query — select/insert/update/delete, conditions, joins, aggregation
  • db & scan — connections, transactions, row mapping
  • Migrations & CLI — the grain CLI, generation, apply/rollback/status
  • Tutorials — getting started, relationships
Requirements
  • Go 1.25+
  • PostgreSQL 12+
License

Grain is released under the Apache License 2.0. See LICENSE for details.

Directories

Path Synopsis
cmd
grain command
examples
basic command

Jump to

Keyboard shortcuts

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