Skip to content

Commit

Permalink
fix: has many relation with driver.Valuer
Browse files Browse the repository at this point in the history
  • Loading branch information
thecampagnards committed Nov 27, 2024
1 parent 928d077 commit cb8c42c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
55 changes: 55 additions & 0 deletions internal/dbtest/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func TestDB(t *testing.T) {
{testWithForeignKeys},
{testWithForeignKeysHasMany},
{testWithPointerForeignKeysHasMany},
{testWithPointerForeignKeysHasManyWithDriverValuer},
{testInterfaceAny},
{testInterfaceJSON},
{testScanRawMessage},
Expand Down Expand Up @@ -1172,6 +1173,60 @@ func testWithPointerForeignKeysHasMany(t *testing.T, db *bun.DB) {
require.Len(t, deck.Users, 2)
}

func testWithPointerForeignKeysHasManyWithDriverValuer(t *testing.T, db *bun.DB) {
type User struct {
ID *int `bun:",pk"`
DeckID sql.NullInt64
Name string
}
type Deck struct {
ID int64 `bun:",pk"`
Users []*User `bun:"rel:has-many,join:id=deck_id"`
}

if db.Dialect().Name() == dialect.SQLite {
_, err := db.Exec("PRAGMA foreign_keys = ON;")
require.NoError(t, err)
}

for _, model := range []interface{}{(*Deck)(nil), (*User)(nil)} {
_, err := db.NewDropTable().Model(model).IfExists().Exec(ctx)
require.NoError(t, err)
}

mustResetModel(t, ctx, db, (*User)(nil))
_, err := db.NewCreateTable().
Model((*Deck)(nil)).
IfNotExists().
WithForeignKeys().
Exec(ctx)
require.NoError(t, err)
mustDropTableOnCleanup(t, ctx, db, (*Deck)(nil))

deckID := int64(1)
deck := Deck{ID: deckID}
_, err = db.NewInsert().Model(&deck).Exec(ctx)
require.NoError(t, err)

userID1 := 1
userID2 := 2
users := []*User{
{ID: &userID1, DeckID: sql.NullInt64{Int64: deckID, Valid: true}, Name: "user 1"},
{ID: &userID2, DeckID: sql.NullInt64{Int64: deckID, Valid: true}, Name: "user 2"},
}

res, err := db.NewInsert().Model(&users).Exec(ctx)
require.NoError(t, err)

affected, err := res.RowsAffected()
require.NoError(t, err)
require.Equal(t, int64(2), affected)

err = db.NewSelect().Model(&deck).Relation("Users").Scan(ctx)
require.NoError(t, err)
require.Len(t, deck.Users, 2)
}

func testInterfaceAny(t *testing.T, db *bun.DB) {
switch db.Dialect().Name() {
case dialect.MySQL:
Expand Down
9 changes: 8 additions & 1 deletion model_table_has_many.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bun
import (
"context"
"database/sql"
"database/sql/driver"
"fmt"
"reflect"

Expand Down Expand Up @@ -152,7 +153,13 @@ func modelKey(key []interface{}, strct reflect.Value, fields []*schema.Field) []
// The value is then used as a map key.
func indirectFieldValue(field reflect.Value) interface{} {
if field.Kind() != reflect.Ptr {
return field.Interface()
i := field.Interface()
if valuer, ok := i.(driver.Valuer); ok {
if v, err := valuer.Value(); err == nil {
return v
}
}
return i
}
if field.IsNil() {
return nil
Expand Down

0 comments on commit cb8c42c

Please sign in to comment.