Skip to content

Latest commit

History

166 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

bake

A database model code generator for Go. Generate ORM models from database schema using bun framework.

Features

  • Supports MySQL and PostgreSQL databases
  • Automatic Go type mapping for database columns
  • Automatic foreign key detection and relation generation (belongs-to, has-many)
  • Composite unique index detection (unique, unique:index_name tags)
  • Customizable templates
  • Custom struct generation — define non-DB structs for JSON columns, value objects, configuration objects
  • Custom field names, types, comments, tags, and multi-line comments
  • Naming conventions (snake_case, camelCase, consecutive acronyms)
  • Timezone support for created_at, updated_at, deleted_at hooks
  • Environment-based configuration (e.g., bake.gen.dev.yaml for env=dev)
  • Concurrent table processing
  • Auto-detect database driver from DSN scheme

Generated Expressions

For each table, bake generates two files:

  • <table>.gen.go — base constants, struct, time hooks
  • <table>.alias.gen.go — alias-prefixed constants for joined queries
CategoryExpressionsDescription
ColumnEq, NeqEquality comparisons
OrderedGt, Gte, Lt, LteOrdering comparisons
StringLike, LikePrefix, LikeSuffix, LikeContain, NotLike, ConcatExprPattern matching
StringLengthExpr, LowerExpr, UpperExprString functions
NumericIn, NotIn, Between, NotBetweenRange operations
AggregateSUMExpr, AVGExpr, MINExpr, MAXExprAggregate functions
ArithmeticAddExpr, SubExpr, MulExpr, DivExprArithmetic assignment
ArithmeticAddLeastExpr, SubGreatestExpr, ClampExprBounded arithmetic
DistinctDistinctExpr, CountDistinctExprDeduplication
NullableIsNull, IsNotNull, CoalesceExprNULL handling
TimeDateExpr, YearExpr, MonthExpr, DayExpr, HourExpr, MinuteExpr, SecondExprTime extraction
OrderingAsc, DescSort order
JoinInnerJoin, LeftJoin, RightJoin, FullJoin (alias file, FullJoin skipped on MySQL)JOIN helpers

Installation

go install github.com/sishui/bake/cmd/bake@latest

Quick Start

  1. Initialize a configuration file:
bake init
  1. Edit bake.gen.yaml with your database connection details

  2. Generate models:

bake

Commands

CommandDescription
bake initInitialize a configuration file in current directory
bake versionShow current version
bakeGenerate models based on configuration

Configuration

Basic Configuration

log:
file: ""# log file path (optional; level defaults to "info")uncountables: ["sms", "mms", "rls"] # words that should not be pluralizedinitialisms: ["ID", "URL", "URI", "UUID", "IP"] # naming conventionstimezone: "Asia/Shanghai"# timezone for time hookstemplate:
dir: ""# custom template directoryoutput:
dir: "model"# output directorypackage: "model"# package namemodule: "github.com/username/project"# module path for importscustom: [] # custom struct definitions (not tied to db tables)db:
- driver: "postgres"dsn: "postgres://user:pass@localhost:5432/db?sslmode=disable"schema: "public"# required for postgres, omitted for mysqlinclude: [] # tables to include (default: all)exclude: [] # tables to exclude (default: none)custom: {} # per-table custom field/tag overrides

Environment-based Configuration

When .env contains env=dev, bake looks for bake.gen.dev.yaml first, then falls back to bake.gen.yaml.

Custom Table Settings

db:
- driver: "postgres"# ...custom:
users:
comment: "User table"# custom table commenttags:
- key: "form"name: "$SnakeCase"# convert to snake_case
- key: "xml"name: "$CamelCase"# convert to camelCasefields:
created_at: # database column namename: "CreatedAt"# custom field nametags:
- key: "json"name: "created_at"# custom json tag nameposts:
fields:
author_id:
name: "Author"# custom field nametype: "*User"# custom field typerelation: true # is a relationtags:
- key: "bun"options: ["rel:belongs", "join:author_id=id"]

Tag Name Transformations

ValueDescription
$SnakeCaseConvert to snake_case
$CamelCaseConvert to camelCase
#field_nameUse literal value

Template Data Structure

You can use custom templates. The following data is passed to templates:

typeModelstruct {
Versionstring// bake versionModulestring// module pathPackagestring// package nameImports [][]string// importsBunModelstring// bun.BaseModelDriverstring// database driver: mysql, postgresTablestring// table nameModelstring// model nameAliasstring// model aliasComments []string// model commentsFields []*Field// fieldsTimezonestring// timezoneCreatedAtTypestring// created_at typeUpdatedAtTypestring// updated_at typeDeletedAtTypestring// deleted_at typeMaxFieldLengthint// max field lengthMaxNullableLengthint// max nullable lengthMaxStringLengthint// max string lengthMaxNumericLengthint// max numeric lengthMaxOrderedLengthint// max ordered lengthMaxOrderedNonStringLengthint// max ordered non-string length (numeric + time)MaxEquatableLengthint// max equatable lengthMaxRelationLengthint// max relation lengthMaxArithmeticLengthint// max arithmetic length (non-pk numeric)MaxTimeLengthint// max time length
}
typeFieldstruct {
Imports []string// field importsNamestring// field nameAlignedNamestring// aligned field nameTypestring// Go typeAlignedTypestring// aligned typeTagstring// field tagsAlignedTagstring// aligned tagComments []string// field commentsColumnNamestring// database column nameKindstring// field kind: NUMERIC, STRING, TIME, etc.IsPrimarybool// is primary keyIsNullablebool// is nullableIsCustombool// is custom fieldIsRelationbool// is relation field
}

Custom Struct Template Data

When using the custom template (default: custom.tmpl), the following data is passed:

typeCustomStructstruct {
Versionstring// bake versionPackagestring// package nameModulestring// module pathImports [][]string// grouped importsNamestring// struct name (PascalCase)Comment []string// struct-level comment linesFields []*StructField// fields in this struct
}
typeStructFieldstruct {
Namestring// Go field name (PascalCase)AlignedNamestring// Name padded to max widthGoTypestring// Go typeAlignedTypestring// GoType padded to max widthTagstring// Struct tag (including backticks)AlignedTagstring// Tag padded to max widthComment []string// Multi-line comment
}
Generated features:
-**Fieldalignment**Names, types, andtagsarealignedwithpadding-**Multi-linecomments**Renderedbeforethefield, tagalignmentisskippedforfieldswithmulti-linecomments-**Commentgroups**Multi-linecommentfieldsseparatestructfieldsintoalignmentgroups-**Scan/Value**Eachstructgets`Scan(src any)`and`Value() (driver.Value, error)`methodsfor`database/sql`compatibility
## TypeMappings
### MySQL|MySQLType|GoType||-------------------|---------------||tinyint(1) |bool||tinyint|int8/uint8||smallint|int16/uint16||int|int32/uint32||bigint|int64/uint64||float|float32||double|float64||decimal|decimal.Decimal||varchar, text|string||blob| []byte||datetime, timestamp|time.Time||json|json.RawMessage||enum, set|string||geometry, point, linestring, polygon, etc. | []byte (WKB) |
### PostgreSQL|PostgreSQLType|GoType||---------------------|---------------------------------------||int2|int16||int4|int32||int8|int64||float4|float32||float8|float64||numeric, decimal|decimal.Decimal||bool|bool||text, varchar|string||bytea| []byte||timestamp, date, time|time.Time||json, jsonb|json.RawMessage||uuid|uuid.UUID||inet, cidr|net.IP||interval|time.Duration||ARRAY| []string, []int32, []int64, []uuid.UUID||geometry, geography, point, etc. (PostGIS) | []byte (WKB) |
## GeneratedBunTagsbakeautomaticallygeneratesbunstructtagsforeachcolumnbasedonthedatabase schema.
### IndexTags|Scenario|GeneratedTag|Description||----------|--------------|-------------||Primarykey|`pk,autoincrement`|Primarykeycolumn||Single-columnuniqueindex|`unique`|Columnhasauniqueconstraint||Compositeuniqueindex|`unique:index_name`|Columnispartofamulti-columnuniqueindex|Exampleforacompositeuniqueindexon`(start_at, end_at)`:
```goStartAt time.Time `bun:"start_at,unique:idx_unique_range,notnull"`EndAt time.Time `bun:"end_at,unique:idx_unique_range,notnull"`

Column Tags

PropertyTagCondition
notnullNon-nullable columnIS_NOT_NULL or NOT NULL
nullzeroNullable columnIS_NULL or nullable
default:valueHas default valueColumn has a default
soft_deleteSoft delete columnColumn name is deleted_at
type:decimal(M,N)Decimal typeMySQL/PostgreSQL decimal columns

Foreign Key Relations

bake automatically detects foreign key relationships from your database schema and generates the appropriate bun relation tags.

How It Works

When a column has a foreign key constraint:

-- posts.user_id references users.idALTERTABLE posts ADD CONSTRAINT fk_posts_user_id
FOREIGN KEY (user_id) REFERENCES users(id);

bake will automatically:

  1. On posts table: Generate User *User field with rel:belongs-to
  2. On users table: Generate Posts []*Post field with rel:has-many

Generated Example

For the posts table with user_id foreign key:

// Post structtypePoststruct {
bun.BaseModel`bun:"table:posts"`IDint64`bun:"id,pk,autoincrement"`UserIDint64`bun:"user_id,notnull"`Titlestring`bun:"title,notnull"`User*User`bun:"user,rel:belongs-to,join:user_id=id"`
}
// User struct (auto-generated reverse relation)typeUserstruct {
bun.BaseModel`bun:"table:users"`IDint64`bun:"id,pk,autoincrement"`Namestring`bun:"name,notnull"`Posts []*Post`bun:"posts,rel:has-many,join:id=user_id"`
}

Manual Override

You can still manually configure relations using the custom configuration. Manual configuration takes precedence over automatic detection.

Custom Structs

Custom structs allow you to define Go structs that are not tied to database tables. They are generated with Scan and Value methods for database/sql compatibility, making them ideal for JSON/JSONB column types.

Usage

Define custom structs in your bake.gen.yaml:

output:
dir: "model"package: "model"module: "github.com/user/project"custom:
- name: "Config"comment: "Application configuration stored as JSONB"fields:
- name: "Theme"type: "string"comment: "UI theme (light/dark)"
- name: "Notifications"type: "bool"comment: "Enable push notifications"
- name: "Description"type: "string"comment: "A detailed description\nwith multiple lines"

Generated Output

Running bake generates one file per custom struct (e.g., model/config.gen.go):

// Code generated by bake. DO NOT EDIT.// version: v0.4.0package model
import (
"database/sql/driver""encoding/json""fmt"
)
// Application configuration stored as JSONBtypeConfigstruct {
// A detailed description// with multiple linesDescriptionstring`json:"description,omitempty"`Notificationsbool`json:"notifications,omitempty"`// Enable push notificationsThemestring`json:"theme,omitempty"`// UI theme (light/dark)
}
func (o*Config) Scan(srcany) error {
ifsrc==nil {
returnnil
}
switchv:=src.(type) {
case []byte:
returnjson.Unmarshal(v, o)
casestring:
returnjson.Unmarshal([]byte(v), o)
default:
returnfmt.Errorf("unsupported scan type %T for Config", src)
}
}
func (oConfig) Value() (driver.Value, error) {
returnjson.Marshal(o)
}

Field Alignment

Fields within the same comment group are aligned for readability:

Group conditionAlignment behavior
Consecutive single-line commentsNames/types/tags are aligned to the widest value in the group
Multi-line comment fieldThe field's tag is not padded; creates a new alignment group
No commentRendered with // suffix and aligned normally

Example

See examples/mysql/ or examples/postgres/ for complete working examples with custom structs integrated alongside database models.

Development

Running Tests

go test ./...

Building

go build ./cmd/bake

License

Apache License 2.0 - see LICENSE file

About

bun orm model gen

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages