uptrace / bun

SQL-first Golang ORM
https://bun.uptrace.dev
BSD 2-Clause "Simplified" License
3.64k stars 220 forks source link

nullzero relations not being fetched #955

Open kubakl opened 8 months ago

kubakl commented 8 months ago

When defining a nullzero relation it fails when using Scan(). Example:

type MainTable struct {
    ID int64 `bun:",pk,notnull`
    ChildID int64
    Child *Parent `bun:",rel:has-one,join:child_id=id"`
}

type Parent struct {
    ID int64 `bun:",pk,notnull"`
    ChildID int64 `bun:",nullzero"`
    Child *Child `bun:",rel:has-one,join:child_id=id"`
}

type Child struct {
    ID int64
    ...
}

With this structure when I try to fetch MainTable and add a relation using Relation("Child.Child") it rather returns no element even though it exists and can be fetched directly or panics with:

reflect: call of reflect.Value.Field on ptr Value

I found a similar issue here, not sure if it's related https://github.com/uptrace/bun/issues/799

codeliger commented 6 months ago

https://github.com/uptrace/bun/issues/943

If i understand correctly i have the same issue here.

JunNishimura commented 5 months ago

@kubakl

I have implemented it as you have shown as an example in the following way, but I could not reproduce the bug.

type Child struct {
    ID int `bun:"id,pk,notnull"`
}

type Parent struct {
    ID      int `bun:"id,pk,notnull"`
    ChildID int
    Child   *Child `bun:"rel:has-one,join:child_id=id"`
}

type Main struct {
    ID      int `bun:"id,pk,notnull"`
    ChildID int
    Child   *Parent `bun:"rel:has-one,join:child_id=id"`
}
func main() {
    ...

    db := bun.NewDB(sqlDB, mysqldialect.New())

    db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))

    ctx := context.Background()

    // Create tables
    if _, err := db.NewDropTable().Model((*Main)(nil)).IfExists().Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    if _, err := db.NewDropTable().Model((*Parent)(nil)).IfExists().Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    if _, err := db.NewDropTable().Model((*Child)(nil)).IfExists().Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    if _, err := db.NewCreateTable().Model((*Child)(nil)).Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    if _, err := db.NewCreateTable().Model((*Parent)(nil)).Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    if _, err := db.NewCreateTable().Model((*Main)(nil)).Exec(ctx); err != nil {
        log.Fatalf("create table failed: %v", err)
    }
    // Insert data
    if _, err := db.NewInsert().Model(&Child{ID: 1}).Exec(ctx); err != nil {
        log.Fatalf("insert failed: %v", err)
    }
    if _, err := db.NewInsert().Model(&Parent{ID: 1, ChildID: 1}).Exec(ctx); err != nil {
        log.Fatalf("insert failed: %v", err)
    }
    if _, err := db.NewInsert().Model(&Main{ID: 1, ChildID: 1}).Exec(ctx); err != nil {
        log.Fatalf("insert failed: %v", err)
    }
    // Select data
    var main Main
    if err := db.NewSelect().Model(&main).Relation("Child.Child").Where("main.id = ?", 1).Scan(ctx); err != nil {
        log.Fatalf("select failed: %v", err)
    }
    log.Printf("%+v", main) // result: {ID:1 ChildID:1 Child:0xc00020c2a0}
}

Could you please tell me a bit more about under what conditions the bug occurred (which RDBMS, which version of Bun)?

kubakl commented 1 month ago

@JunNishimura I can see you're not checking it like the description specifies this happens when the ChildID in the Parent table has bun:",nullzero" specified. This doesn't work for me, I'm using postgres lib and I'm working on bun version v1.1.14