Skip to content

Commit

Permalink
fix "model does not have column" error
Browse files Browse the repository at this point in the history
This fixes the case of two belongs-to fields with different names
but with the same type.
  • Loading branch information
martoche committed Jun 6, 2023
1 parent dacffd2 commit d1d1fc7
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 5 deletions.
83 changes: 83 additions & 0 deletions internal/dbtest/orm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func TestORM(t *testing.T) {
{testM2MRelationExcludeColumn},
{testRelationBelongsToSelf},
{testCompositeHasMany},
{testRelationsDifferentFieldsWithSameType},
}

testEachDB(t, func(t *testing.T, dbName string, db *bun.DB) {
Expand Down Expand Up @@ -442,6 +443,88 @@ func testCompositeHasMany(t *testing.T, db *bun.DB) {
require.Equal(t, 2, len(department.Employees))
}

func testRelationsDifferentFieldsWithSameType(t *testing.T, db *bun.DB) {
type Address struct {
Id int `bun:",pk"`
}

type CompanyAddress struct {
Id int `bun:",pk"`
CompanyId int
BillingAddressId int
BillingAddress *Address `bun:"rel:belongs-to,join:billing_address_id=id"`
ShippingAddressId int
ShippingAddress *Address `bun:"rel:belongs-to,join:shipping_address_id=id"`
}

type Company struct {
Id int `bun:",pk"`
ParentCompanyId int
CompanyAddress *CompanyAddress `bun:"rel:has-one,join:id=company_id"`
}

type ParentCompany struct {
Id int `bun:",pk"`
Companies []*Company `bun:"rel:has-many,join:id=parent_company_id"`
}

models := []interface{}{
(*Address)(nil),
(*CompanyAddress)(nil),
(*Company)(nil),
(*ParentCompany)(nil),
}
for _, model := range models {
_, err := db.NewDropTable().Model(model).IfExists().Exec(ctx)
require.NoError(t, err)
_, err = db.NewCreateTable().Model(model).Exec(ctx)
require.NoError(t, err)
}

models = []interface{}{
&Address{Id: 1},
&Address{Id: 2},
&CompanyAddress{Id: 1, CompanyId: 1, BillingAddressId: 1, ShippingAddressId: 2},
&Company{Id: 1, ParentCompanyId: 1},
&ParentCompany{Id: 1},
}
for _, model := range models {
res, err := db.NewInsert().Model(model).Exec(ctx)
require.NoError(t, err)

n, err := res.RowsAffected()
require.NoError(t, err)
require.Equal(t, int64(1), n)
}

var parentCompany ParentCompany
err := db.NewSelect().
Model(&parentCompany).
Relation("Companies.CompanyAddress.BillingAddress").
Relation("Companies.CompanyAddress.ShippingAddress").
Where("id = ?", 1).
Scan(ctx)

require.NoError(t, err)
require.Equal(t, ParentCompany{
Id: 1,
Companies: []*Company{
{
Id: 1,
ParentCompanyId: 1,
CompanyAddress: &CompanyAddress{
Id: 1,
CompanyId: 1,
BillingAddressId: 1,
BillingAddress: &Address{Id: 1},
ShippingAddressId: 2,
ShippingAddress: &Address{Id: 2},
},
},
},
}, parentCompany)
}

type Genre struct {
ID int `bun:",pk"`
Name string
Expand Down
25 changes: 20 additions & 5 deletions schema/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,25 @@ func (t *Table) m2mRelation(field *Field) *Relation {
return rel
}

func (t *Table) inlineFields(field *Field, seen map[reflect.Type]struct{}) {
type inlineFieldsSeenKey struct {
TableType reflect.Type
StructFieldName string
}

func (t *Table) inlineFields(field *Field, seen map[inlineFieldsSeenKey]struct{}) {
if seen == nil {
seen = map[reflect.Type]struct{}{t.Type: {}}
seen = map[inlineFieldsSeenKey]struct{}{}
}

key := inlineFieldsSeenKey{
TableType: t.Type,
StructFieldName: field.StructField.Name,
}

if _, ok := seen[field.IndirectType]; ok {
if _, ok := seen[key]; ok {
return
}
seen[field.IndirectType] = struct{}{}
seen[key] = struct{}{}

joinTable := t.dialect.Tables().Ref(field.IndirectType)
for _, f := range joinTable.allFields {
Expand All @@ -834,7 +844,12 @@ func (t *Table) inlineFields(field *Field, seen map[reflect.Type]struct{}) {
continue
}

if _, ok := seen[f.IndirectType]; !ok {
key := inlineFieldsSeenKey{
TableType: t.Type,
StructFieldName: f.StructField.Name,
}

if _, ok := seen[key]; !ok {
t.inlineFields(f, seen)
}
}
Expand Down

0 comments on commit d1d1fc7

Please sign in to comment.