bun
bun copied to clipboard
Error `bun: TableName does not have column=ColumnName"` on relations nested inside a has-many relation
I found a bug that seems to happen with queries that include a has-many relation and nested relations that refer to the same table (not very clear I know, refer to the reproducer bellow). It took me some time to pinpoint the cause of the problem but I eventually found it. I will attach a PR to this issue with the fix I came up with.
package main
import (
"context"
"database/sql"
"encoding/json"
"fmt"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
type Foo struct {
Id int64 `bun:",pk,autoincrement,nullzero"`
Name string
Bars []*Bar `bun:"rel:has-many,join:id=foo_id"`
}
type Bar struct {
Id int64 `bun:",pk,nullzero"`
Name string
FooId int64 `bun:",nullzero"`
BazId int64 `bun:",nullzero"`
Baz *Baz `bun:"rel:belongs-to,join:baz_id=id"`
Quux *Quux `bun:"rel:has-one,join:id=id"`
}
type Baz struct {
Id int64 `bun:",pk,nullzero"`
Name string
QuxId int64 `bun:",nullzero"`
Qux *Qux `bun:"rel:belongs-to,join:qux_id=id"`
Quux *Quux `bun:"rel:has-one,join:id=id"`
}
type Qux struct {
Id int64 `bun:",pk,nullzero"`
Name string
Quux *Quux `bun:"rel:has-one,join:id=id"`
}
type Quux struct {
Id int64 `bun:",pk,autoincrement,nullzero"`
Name string
}
func main() {
pgServer := embeddedpostgres.NewDatabase(
embeddedpostgres.DefaultConfig().Logger(nil),
)
err := pgServer.Start()
if err != nil {
panic(err)
}
defer pgServer.Stop()
ctx := context.Background()
dsn := "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable"
sqlDb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
db := bun.NewDB(sqlDb, pgdialect.New())
_, err = db.NewCreateTable().
Model((*Foo)(nil)).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewCreateTable().
Model((*Bar)(nil)).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewCreateTable().
Model((*Baz)(nil)).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewCreateTable().
Model((*Quux)(nil)).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewCreateTable().
Model((*Qux)(nil)).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Quux{
{Name: "quux_qux"},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Quux{
{Name: "quux_baz"},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Quux{
{Name: "quux_bar"},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Qux{
{Name: "qux", Id: 1},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Baz{
{Name: "baz", Id: 2, QuxId: 1},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Bar{
{Name: "bar", Id: 3, FooId: 1, BazId: 2},
}).
Exec(ctx)
if err != nil {
panic(err)
}
_, err = db.NewInsert().
Model(&[]*Foo{
{Name: "foo"},
}).
Exec(ctx)
if err != nil {
panic(err)
}
res := Foo{}
err = db.NewSelect().
Model(&res).
Where("id = 1").
Relation("Bars").
Relation("Bars.Quux").
Relation("Bars.Baz").
Relation("Bars.Baz.Quux").
Relation("Bars.Baz.Qux").
Relation("Bars.Baz.Qux.Quux").
Scan(ctx)
if err != nil {
panic(err)
}
resJson, _ := json.MarshalIndent(res, "", " ")
fmt.Println(string(resJson))
}
Seems like I stumbled across the same issue. My scenario is rather simple: A is my reference point and I'm joining B, C and finally D. Somehow only C gets an error on the last field. The revert of #850 seems to trade in quality for memory, doesn't it? Is there any plan to fix this again?