diff --git a/orm/db_utils.go b/orm/db_utils.go index 923917ec..7ae10ca5 100644 --- a/orm/db_utils.go +++ b/orm/db_utils.go @@ -41,6 +41,8 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac vu := v.Int() exist = true value = vu + } else if fi.fieldType&IsRelField > 0 { + _, value, exist = getExistPk(fi.relModelInfo, reflect.Indirect(v)) } else { vu := v.String() exist = vu != "" diff --git a/orm/models_test.go b/orm/models_test.go index 462370b2..9843a87d 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -406,6 +406,11 @@ type UintPk struct { Name string } +type PtrPk struct { + ID *IntegerPk `orm:"pk;rel(one)"` + Positive bool +} + var DBARGS = struct { Driver string Source string diff --git a/orm/orm.go b/orm/orm.go index 538916e4..d9d1cd77 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -153,6 +153,8 @@ func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, i id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex) if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { id = int64(vid.Uint()) + } else if mi.fields.pk.rel { + return o.ReadOrCreate(vid.Interface(), mi.fields.pk.relModelInfo.fields.pk.name) } else { id = vid.Int() } diff --git a/orm/orm_test.go b/orm/orm_test.go index adfe0066..8738952b 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -193,6 +193,7 @@ func TestSyncDb(t *testing.T) { RegisterModel(new(InLineOneToOne)) RegisterModel(new(IntegerPk)) RegisterModel(new(UintPk)) + RegisterModel(new(PtrPk)) err := RunSyncdb("default", true, Debug) throwFail(t, err) @@ -216,6 +217,7 @@ func TestRegisterModels(t *testing.T) { RegisterModel(new(InLineOneToOne)) RegisterModel(new(IntegerPk)) RegisterModel(new(UintPk)) + RegisterModel(new(PtrPk)) BootStrap() @@ -2144,6 +2146,48 @@ func TestUintPk(t *testing.T) { dORM.Delete(u) } +func TestPtrPk(t *testing.T) { + parent := &IntegerPk{ID: 10, Value: "10"} + + id, _ := dORM.Insert(parent) + if !IsMysql { + // MySql does not support last_insert_id in this case: see #2382 + throwFail(t, AssertIs(id, 10)) + } + + ptr := PtrPk{ID: parent, Positive: true} + num, err := dORM.InsertMulti(2, []PtrPk{ptr}) + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + throwFail(t, AssertIs(ptr.ID, parent)) + + nptr := &PtrPk{ID: parent} + created, pk, err := dORM.ReadOrCreate(nptr, "ID") + throwFail(t, err) + throwFail(t, AssertIs(created, false)) + throwFail(t, AssertIs(pk, 10)) + throwFail(t, AssertIs(nptr.ID, parent)) + throwFail(t, AssertIs(nptr.Positive, true)) + + nptr = &PtrPk{Positive: true} + created, pk, err = dORM.ReadOrCreate(nptr, "Positive") + throwFail(t, err) + throwFail(t, AssertIs(created, false)) + throwFail(t, AssertIs(pk, 10)) + throwFail(t, AssertIs(nptr.ID, parent)) + + nptr.Positive = false + num, err = dORM.Update(nptr) + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + throwFail(t, AssertIs(nptr.ID, parent)) + throwFail(t, AssertIs(nptr.Positive, false)) + + num, err = dORM.Delete(nptr) + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) +} + func TestSnake(t *testing.T) { cases := map[string]string{ "i": "i",