anetos gen reference
anetos gen writes the typed columns of your models. It is part of the
anetos developer tool (module anetos.dev/anetos/cli). See
Generate typed columns for a walkthrough.
Installing and running
| Command | Does |
|---|---|
go get -tool anetos.dev/anetos/cli/cmd/anetos@latest | Adds the tool to your module’s go.mod |
go tool anetos gen [packages] | Generates for the packages (default ./..., relative to the current directory) |
go tool anetos gen -check [packages] | Writes nothing; exits with status 1 and lists the out-of-date files |
go tool anetos version | Prints the tool’s version |
//go:generate go tool anetos gen | Runs it from go generate ./... |
Package patterns are the ones go build takes. Exit status: 0 on
success, 1 on errors (or out-of-date files with -check), 2 for bad
usage.
Which structs are models
A named, non-generic struct type declared at package level (in a non-test file) is a model when it:
| Rule | Example |
|---|---|
Embeds db.Model, db.Timestamps or db.SoftDeletes, directly or through embedded structs | type Post struct { db.Model; … } |
Has a TableName() string method (value or pointer receiver) | func (Setting) TableName() string |
Has //anetos:model in its doc comment | a plain struct |
Models, and the structs of their package they embed, must be in files
without build constraints (no //go:build line, no _linux.go-style
name), so the generated file is the same on every platform. //anetos:skip in the doc comment excludes a struct. Any other
//anetos: directive is an error. Structs that scan themselves
(sql.Scanner, driver.Valuer, time.Time) are values, not models.
What is generated
One file per package, models_gen.go, starting with
// Code generated by anetos gen. DO NOT EDIT. For each model Name in
source order:
// illustrative
// NameCols are the columns of [Name].
var NameCols = struct {
Field db.Column[FieldType]
…
}{
Field: db.Col[FieldType]("column"),
…
}| Field | Generated |
|---|---|
Title string | Title db.Column[string], column title |
AuthorID int64 \db:“author”`` | AuthorID db.Column[int64], column author |
PublishedAt *time.Time | db.Column[*time.Time] (compare with new(t), set NULL with nil) |
Tags []string \db:“tags,json”`` | db.Column[[]string] made with db.JSONCol |
Fields of embedded structs (db.Model: ID, CreatedAt, UpdatedAt) | Flattened in place, like the runtime |
Author *User \rel:“belongs_to”`, Comments []Comment `rel:“has_many”`` | A relation handle in PostRels: Author db.Rel[Post, User], made with db.RelOf[Post, User]("Author") |
| Untagged struct, pointer-to-struct and slice-of-struct fields | Nothing |
db:"-" and unexported fields | Nothing |
The column rules are the db package’s
(models reference). The generated names are the struct
field names; an unexported model post gets postCols. Imports get
another name (time2) when the package already declares that name in
any of its files (in-package tests and other platforms’ files included).
Files it manages
- It only overwrites or removes a
models_gen.gothat starts with its header (Unix or Windows line endings); any other file with that name is an error, even one excluded from the build. - It removes
models_gen.gofrom a package with no models left. - It ignores the current
models_gen.gowhile reading the package, and compile errors outside model fields (such as code using a column not generated yet). Syntax errors, and type errors in a model’s fields, stop it. - Packages are only type-checked when they import the
dbpackage (directly or not), mentionTableNameor a//anetos:directive, or already have amodels_gen.go.
Errors
| Message | Meaning |
|---|---|
two fields map to column "x" | Two fields have the same column name |
unknown db tag option "x" (known: pk, json, readonly) | A typo in a db tag |
more than one pk field | Composite keys aren’t supported by models |
columns "a" and "b" both come from fields named X | Two fields (one embedded) share a Go name; rename one |
XCols is already declared, XRels is already declared | The package declares a name anetos gen needs |
unknown relation "x", bad has_many option "x" | A typo in a rel tag |
a has_many relation is a slice of models, … a pointer to a model | The field’s type doesn’t fit the relation kind |
field X has a db tag and a rel tag | A field is a column or a relation, not both |
field X has …, which package … can't name | An embedded struct from another package has a field of an unexported type, a type from an internal package yours can’t import, or an anonymous struct with unexported fields; tag it db:"-" or change the embedded struct |
models in files with build constraints aren't supported, embeds X, declared in a file with build constraints | The model, or a struct of the package it embeds, is in a _linux.go-style file or one with a //go:build line: the generated file would differ per platform |
embeds itself | A struct embeds itself through a pointer |
generic types and aliases can't be models | //anetos:model on a generic type or alias |
is marked //anetos:model but is not a model struct | The type isn’t a struct, or scans itself |
models_gen.go was not written by anetos gen | Rename your file |