Skip to main content

Field pointers as column names: compile-checked Go queries without codegen

· 13 min read
Alberts Liepiņš
Maintainer of ant

Go database libraries make you pick one of two trades. GORM and Bun take column names as strings, so "agee > ?" builds fine and fails the first time it runs. ent and sqlc check every column at build time, but they get there through a schema file or a folder of SQL, plus a generate step that has to run before your code compiles.

I wanted the checking without the generator. Go 1.27 added generic methods, and that turned out to be the missing piece: a chainable query API can now take pointers to your own struct fields as column names. ant.Gt(&Users.Age, 18) names the age column, and the compiler checks both that Age exists and that 18 is the right type for it. Nothing is generated.

This post is about how that works, what it costs at runtime, and the places where it still fails after compiling. The library is ant, which I maintain.