Shared tables and views
A model usually has a table to itself. These are the cases where it doesn't.
One table, several models
Go has no inheritance, so each model is its own plain struct, and a discriminator column says which rows belong to which. Inserts set it for you, and each model's queries only see its own rows.
type Dog struct {
ID int64
Kind string
Name string
Barks *int
}
func (Dog) Configure(b *ant.ModelBuilder[Dog]) {
b.Table("animals")
b.Discriminator(&DG.Kind, "dog")
}
type Cat struct {
ID int64
Kind string
Name string
Lives *int
}
func (Cat) Configure(b *ant.ModelBuilder[Cat]) {
b.Table("animals")
b.Discriminator(&CT.Kind, "cat")
}
var (
DG = ant.Fields[Dog]()
CT = ant.Fields[Cat]()
)
Migrations see one table, and a column only one model declares allows NULL.
Models can also share a table with no discriminator, which is table splitting: a small model for the common read, and a full one for the rest.
type UserName struct {
ID int64
Name string
}
func (UserName) Configure(b *ant.ModelBuilder[UserName]) {
b.Table("users")
}
For a separate table per type, embed a shared struct in each model. That's plain Go, and no ant feature is involved.
Views
b.View maps a model to a view. It reads like a table, and refuses every write with ant.ErrReadOnly. Define the view itself in migrations/code.
type ActiveUser struct {
ID int64
Name string
}
func (ActiveUser) Configure(b *ant.ModelBuilder[ActiveUser]) {
b.View("active_users")
}
Schemas
b.Schema places a table in a database schema. Migrations create the schema and qualify everything.
func (Invoice) Configure(b *ant.ModelBuilder[Invoice]) {
b.Schema("billing")
}
See it tested: tests/features/model_definition/inheritance_test.go