diff --git a/orm/orm.go b/orm/orm.go index 71b4daa4..00439399 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -74,6 +74,20 @@ func (o *orm) Read(md interface{}, cols ...string) error { return nil } +// Try to read a row from the database, or insert one if it doesn't exist +func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) { + cols = append([]string{col1}, cols...) + mi, ind := o.getMiInd(md, true) + err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols) + if err == ErrNoRows { + // Create + id, err := o.Insert(md) + return (err == nil), id, err + } + + return false, ind.Field(mi.fields.pk.fieldIndex).Int(), err +} + // insert model data to database func (o *orm) Insert(md interface{}) (int64, error) { mi, ind := o.getMiInd(md, true) diff --git a/orm/orm_test.go b/orm/orm_test.go index f5101811..c951d5ca 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -1642,3 +1642,41 @@ func TestTransaction(t *testing.T) { throwFail(t, AssertIs(num, 1)) } + +func TestReadOrCreate(t *testing.T) { + u := &User{ + UserName: "Kyle", + Email: "kylemcc@gmail.com", + Password: "other_pass", + Status: 7, + IsStaff: false, + IsActive: true, + } + + created, pk, err := dORM.ReadOrCreate(u, "UserName") + throwFail(t, err) + throwFail(t, AssertIs(created, true)) + throwFail(t, AssertIs(u.UserName, "Kyle")) + throwFail(t, AssertIs(u.Email, "kylemcc@gmail.com")) + throwFail(t, AssertIs(u.Password, "other_pass")) + throwFail(t, AssertIs(u.Status, 7)) + throwFail(t, AssertIs(u.IsStaff, false)) + throwFail(t, AssertIs(u.IsActive, true)) + throwFail(t, AssertIs(u.Created.In(DefaultTimeLoc), u.Created.In(DefaultTimeLoc), test_Date)) + throwFail(t, AssertIs(u.Updated.In(DefaultTimeLoc), u.Updated.In(DefaultTimeLoc), test_DateTime)) + + nu := &User{UserName: u.UserName, Email: "someotheremail@gmail.com"} + created, pk, err = dORM.ReadOrCreate(nu, "UserName") + throwFail(t, err) + throwFail(t, AssertIs(created, false)) + throwFail(t, AssertIs(nu.Id, u.Id)) + throwFail(t, AssertIs(pk, u.Id)) + throwFail(t, AssertIs(nu.UserName, u.UserName)) + throwFail(t, AssertIs(nu.Email, u.Email)) // should contain the value in the table, not the one specified above + throwFail(t, AssertIs(nu.Password, u.Password)) + throwFail(t, AssertIs(nu.Status, u.Status)) + throwFail(t, AssertIs(nu.IsStaff, u.IsStaff)) + throwFail(t, AssertIs(nu.IsActive, u.IsActive)) + + dORM.Delete(u) +} diff --git a/orm/types.go b/orm/types.go index 6f13ed67..76e53017 100644 --- a/orm/types.go +++ b/orm/types.go @@ -23,6 +23,7 @@ type Fielder interface { // orm struct type Ormer interface { Read(interface{}, ...string) error + ReadOrCreate(interface{}, string, ...string) (bool, int64, error) Insert(interface{}) (int64, error) InsertMulti(int, interface{}) (int64, error) Update(interface{}, ...string) (int64, error)