| package gorp |
| |
| import ( |
| "bytes" |
| "database/sql" |
| "encoding/json" |
| "errors" |
| "fmt" |
| "log" |
| "math/rand" |
| "os" |
| "reflect" |
| "strings" |
| "testing" |
| "time" |
| |
| _ "github.com/go-sql-driver/mysql" |
| ) |
| |
| // verify interface compliance |
| var _ Dialect = SqliteDialect{} |
| var _ Dialect = PostgresDialect{} |
| var _ Dialect = MySQLDialect{} |
| var _ Dialect = SqlServerDialect{} |
| var _ Dialect = OracleDialect{} |
| |
| type testable interface { |
| GetId() int64 |
| Rand() |
| } |
| |
| type Invoice struct { |
| Id int64 |
| Created int64 |
| Updated int64 |
| Memo string |
| PersonId int64 |
| IsPaid bool |
| } |
| |
| func (me *Invoice) GetId() int64 { return me.Id } |
| func (me *Invoice) Rand() { |
| me.Memo = fmt.Sprintf("random %d", rand.Int63()) |
| me.Created = rand.Int63() |
| me.Updated = rand.Int63() |
| } |
| |
| type InvoiceTag struct { |
| Id int64 `db:"myid"` |
| Created int64 `db:"myCreated"` |
| Updated int64 `db:"date_updated"` |
| Memo string |
| PersonId int64 `db:"person_id"` |
| IsPaid bool `db:"is_Paid"` |
| } |
| |
| func (me *InvoiceTag) GetId() int64 { return me.Id } |
| func (me *InvoiceTag) Rand() { |
| me.Memo = fmt.Sprintf("random %d", rand.Int63()) |
| me.Created = rand.Int63() |
| me.Updated = rand.Int63() |
| } |
| |
| // See: https://github.com/go-gorp/gorp/issues/175 |
| type AliasTransientField struct { |
| Id int64 `db:"id"` |
| Bar int64 `db:"-"` |
| BarStr string `db:"bar"` |
| } |
| |
| func (me *AliasTransientField) GetId() int64 { return me.Id } |
| func (me *AliasTransientField) Rand() { |
| me.BarStr = fmt.Sprintf("random %d", rand.Int63()) |
| } |
| |
| type OverriddenInvoice struct { |
| Invoice |
| Id string |
| } |
| |
| type Person struct { |
| Id int64 |
| Created int64 |
| Updated int64 |
| FName string |
| LName string |
| Version int64 |
| } |
| |
| type FNameOnly struct { |
| FName string |
| } |
| |
| type InvoicePersonView struct { |
| InvoiceId int64 |
| PersonId int64 |
| Memo string |
| FName string |
| LegacyVersion int64 |
| } |
| |
| type TableWithNull struct { |
| Id int64 |
| Str sql.NullString |
| Int64 sql.NullInt64 |
| Float64 sql.NullFloat64 |
| Bool sql.NullBool |
| Bytes []byte |
| } |
| |
| type WithIgnoredColumn struct { |
| internal int64 `db:"-"` |
| Id int64 |
| Created int64 |
| } |
| |
| type IdCreated struct { |
| Id int64 |
| Created int64 |
| } |
| |
| type IdCreatedExternal struct { |
| IdCreated |
| External int64 |
| } |
| |
| type WithStringPk struct { |
| Id string |
| Name string |
| } |
| |
| type CustomStringType string |
| |
| type TypeConversionExample struct { |
| Id int64 |
| PersonJSON Person |
| Name CustomStringType |
| } |
| |
| type PersonUInt32 struct { |
| Id uint32 |
| Name string |
| } |
| |
| type PersonUInt64 struct { |
| Id uint64 |
| Name string |
| } |
| |
| type PersonUInt16 struct { |
| Id uint16 |
| Name string |
| } |
| |
| type WithEmbeddedStruct struct { |
| Id int64 |
| Names |
| } |
| |
| type WithEmbeddedStructBeforeAutoincrField struct { |
| Names |
| Id int64 |
| } |
| |
| type WithEmbeddedAutoincr struct { |
| WithEmbeddedStruct |
| MiddleName string |
| } |
| |
| type Names struct { |
| FirstName string |
| LastName string |
| } |
| |
| type UniqueColumns struct { |
| FirstName string |
| LastName string |
| City string |
| ZipCode int64 |
| } |
| |
| type SingleColumnTable struct { |
| SomeId string |
| } |
| |
| type CustomDate struct { |
| time.Time |
| } |
| |
| type WithCustomDate struct { |
| Id int64 |
| Added CustomDate |
| } |
| |
| type WithNullTime struct { |
| Id int64 |
| Time NullTime |
| } |
| |
| type testTypeConverter struct{} |
| |
| func (me testTypeConverter) ToDb(val interface{}) (interface{}, error) { |
| |
| switch t := val.(type) { |
| case Person: |
| b, err := json.Marshal(t) |
| if err != nil { |
| return "", err |
| } |
| return string(b), nil |
| case CustomStringType: |
| return string(t), nil |
| case CustomDate: |
| return t.Time, nil |
| } |
| |
| return val, nil |
| } |
| |
| func (me testTypeConverter) FromDb(target interface{}) (CustomScanner, bool) { |
| switch target.(type) { |
| case *Person: |
| binder := func(holder, target interface{}) error { |
| s, ok := holder.(*string) |
| if !ok { |
| return errors.New("FromDb: Unable to convert Person to *string") |
| } |
| b := []byte(*s) |
| return json.Unmarshal(b, target) |
| } |
| return CustomScanner{new(string), target, binder}, true |
| case *CustomStringType: |
| binder := func(holder, target interface{}) error { |
| s, ok := holder.(*string) |
| if !ok { |
| return errors.New("FromDb: Unable to convert CustomStringType to *string") |
| } |
| st, ok := target.(*CustomStringType) |
| if !ok { |
| return errors.New(fmt.Sprint("FromDb: Unable to convert target to *CustomStringType: ", reflect.TypeOf(target))) |
| } |
| *st = CustomStringType(*s) |
| return nil |
| } |
| return CustomScanner{new(string), target, binder}, true |
| case *CustomDate: |
| binder := func(holder, target interface{}) error { |
| t, ok := holder.(*time.Time) |
| if !ok { |
| return errors.New("FromDb: Unable to convert CustomDate to *time.Time") |
| } |
| dateTarget, ok := target.(*CustomDate) |
| if !ok { |
| return errors.New(fmt.Sprint("FromDb: Unable to convert target to *CustomDate: ", reflect.TypeOf(target))) |
| } |
| dateTarget.Time = *t |
| return nil |
| } |
| return CustomScanner{new(time.Time), target, binder}, true |
| } |
| |
| return CustomScanner{}, false |
| } |
| |
| func (p *Person) PreInsert(s SqlExecutor) error { |
| p.Created = time.Now().UnixNano() |
| p.Updated = p.Created |
| if p.FName == "badname" { |
| return fmt.Errorf("Invalid name: %s", p.FName) |
| } |
| return nil |
| } |
| |
| func (p *Person) PostInsert(s SqlExecutor) error { |
| p.LName = "postinsert" |
| return nil |
| } |
| |
| func (p *Person) PreUpdate(s SqlExecutor) error { |
| p.FName = "preupdate" |
| return nil |
| } |
| |
| func (p *Person) PostUpdate(s SqlExecutor) error { |
| p.LName = "postupdate" |
| return nil |
| } |
| |
| func (p *Person) PreDelete(s SqlExecutor) error { |
| p.FName = "predelete" |
| return nil |
| } |
| |
| func (p *Person) PostDelete(s SqlExecutor) error { |
| p.LName = "postdelete" |
| return nil |
| } |
| |
| func (p *Person) PostGet(s SqlExecutor) error { |
| p.LName = "postget" |
| return nil |
| } |
| |
| type PersistentUser struct { |
| Key int32 |
| Id string |
| PassedTraining bool |
| } |
| |
| func TestCreateTablesIfNotExists(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestTruncateTables(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| t.Error(err) |
| } |
| |
| // Insert some data |
| p1 := &Person{0, 0, 0, "Bob", "Smith", 0} |
| dbmap.Insert(p1) |
| inv := &Invoice{0, 0, 1, "my invoice", 0, true} |
| dbmap.Insert(inv) |
| |
| err = dbmap.TruncateTables() |
| if err != nil { |
| t.Error(err) |
| } |
| |
| // Make sure all rows are deleted |
| rows, _ := dbmap.Select(Person{}, "SELECT * FROM person_test") |
| if len(rows) != 0 { |
| t.Errorf("Expected 0 person rows, got %d", len(rows)) |
| } |
| rows, _ = dbmap.Select(Invoice{}, "SELECT * FROM invoice_test") |
| if len(rows) != 0 { |
| t.Errorf("Expected 0 invoice rows, got %d", len(rows)) |
| } |
| } |
| |
| func TestCustomDateType(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TypeConverter = testTypeConverter{} |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTable(WithCustomDate{}).SetKeys(true, "Id") |
| err := dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| |
| test1 := &WithCustomDate{Added: CustomDate{Time: time.Now().Truncate(time.Second)}} |
| err = dbmap.Insert(test1) |
| if err != nil { |
| t.Errorf("Could not insert struct with custom date field: %s", err) |
| t.FailNow() |
| } |
| // Unfortunately, the mysql driver doesn't handle time.Time |
| // values properly during Get(). I can't find a way to work |
| // around that problem - every other type that I've tried is just |
| // silently converted. time.Time is the only type that causes |
| // the issue that this test checks for. As such, if the driver is |
| // mysql, we'll just skip the rest of this test. |
| if _, driver := dialectAndDriver(); driver == "mysql" { |
| t.Skip("TestCustomDateType can't run Get() with the mysql driver; skipping the rest of this test...") |
| } |
| result, err := dbmap.Get(new(WithCustomDate), test1.Id) |
| if err != nil { |
| t.Errorf("Could not get struct with custom date field: %s", err) |
| t.FailNow() |
| } |
| test2 := result.(*WithCustomDate) |
| if test2.Added.UTC() != test1.Added.UTC() { |
| t.Errorf("Custom dates do not match: %v != %v", test2.Added.UTC(), test1.Added.UTC()) |
| } |
| } |
| |
| func TestUIntPrimaryKey(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTable(PersonUInt64{}).SetKeys(true, "Id") |
| dbmap.AddTable(PersonUInt32{}).SetKeys(true, "Id") |
| dbmap.AddTable(PersonUInt16{}).SetKeys(true, "Id") |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| |
| p1 := &PersonUInt64{0, "name1"} |
| p2 := &PersonUInt32{0, "name2"} |
| p3 := &PersonUInt16{0, "name3"} |
| err = dbmap.Insert(p1, p2, p3) |
| if err != nil { |
| t.Error(err) |
| } |
| if p1.Id != 1 { |
| t.Errorf("%d != 1", p1.Id) |
| } |
| if p2.Id != 1 { |
| t.Errorf("%d != 1", p2.Id) |
| } |
| if p3.Id != 1 { |
| t.Errorf("%d != 1", p3.Id) |
| } |
| } |
| |
| func TestSetUniqueTogether(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTable(UniqueColumns{}).SetUniqueTogether("FirstName", "LastName").SetUniqueTogether("City", "ZipCode") |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| |
| n1 := &UniqueColumns{"Steve", "Jobs", "Cupertino", 95014} |
| err = dbmap.Insert(n1) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| // Should fail because of the first constraint |
| n2 := &UniqueColumns{"Steve", "Jobs", "Sunnyvale", 94085} |
| err = dbmap.Insert(n2) |
| if err == nil { |
| t.Error(err) |
| } |
| // "unique" for Postgres/SQLite, "Duplicate entry" for MySQL |
| errLower := strings.ToLower(err.Error()) |
| if !strings.Contains(errLower, "unique") && !strings.Contains(errLower, "duplicate entry") { |
| t.Error(err) |
| } |
| |
| // Should also fail because of the second unique-together |
| n3 := &UniqueColumns{"Steve", "Wozniak", "Cupertino", 95014} |
| err = dbmap.Insert(n3) |
| if err == nil { |
| t.Error(err) |
| } |
| // "unique" for Postgres/SQLite, "Duplicate entry" for MySQL |
| errLower = strings.ToLower(err.Error()) |
| if !strings.Contains(errLower, "unique") && !strings.Contains(errLower, "duplicate entry") { |
| t.Error(err) |
| } |
| |
| // This one should finally succeed |
| n4 := &UniqueColumns{"Steve", "Wozniak", "Sunnyvale", 94085} |
| err = dbmap.Insert(n4) |
| if err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestPersistentUser(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.Exec("drop table if exists PersistentUser") |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key") |
| table.ColMap("Key").Rename("mykey") |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| pu := &PersistentUser{43, "33r", false} |
| err = dbmap.Insert(pu) |
| if err != nil { |
| panic(err) |
| } |
| |
| // prove we can pass a pointer into Get |
| pu2, err := dbmap.Get(pu, pu.Key) |
| if err != nil { |
| panic(err) |
| } |
| if !reflect.DeepEqual(pu, pu2) { |
| t.Errorf("%v!=%v", pu, pu2) |
| } |
| |
| arr, err := dbmap.Select(pu, "select * from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if !reflect.DeepEqual(pu, arr[0]) { |
| t.Errorf("%v!=%v", pu, arr[0]) |
| } |
| |
| // prove we can get the results back in a slice |
| var puArr []*PersistentUser |
| _, err = dbmap.Select(&puArr, "select * from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu, puArr[0]) { |
| t.Errorf("%v!=%v", pu, puArr[0]) |
| } |
| |
| // prove we can get the results back in a non-pointer slice |
| var puValues []PersistentUser |
| _, err = dbmap.Select(&puValues, "select * from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(puValues) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(*pu, puValues[0]) { |
| t.Errorf("%v!=%v", *pu, puValues[0]) |
| } |
| |
| // prove we can get the results back in a string slice |
| var idArr []*string |
| _, err = dbmap.Select(&idArr, "select Id from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(idArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu.Id, *idArr[0]) { |
| t.Errorf("%v!=%v", pu.Id, *idArr[0]) |
| } |
| |
| // prove we can get the results back in an int slice |
| var keyArr []*int32 |
| _, err = dbmap.Select(&keyArr, "select mykey from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(keyArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu.Key, *keyArr[0]) { |
| t.Errorf("%v!=%v", pu.Key, *keyArr[0]) |
| } |
| |
| // prove we can get the results back in a bool slice |
| var passedArr []*bool |
| _, err = dbmap.Select(&passedArr, "select PassedTraining from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(passedArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu.PassedTraining, *passedArr[0]) { |
| t.Errorf("%v!=%v", pu.PassedTraining, *passedArr[0]) |
| } |
| |
| // prove we can get the results back in a non-pointer slice |
| var stringArr []string |
| _, err = dbmap.Select(&stringArr, "select Id from PersistentUser") |
| if err != nil { |
| panic(err) |
| } |
| if len(stringArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu.Id, stringArr[0]) { |
| t.Errorf("%v!=%v", pu.Id, stringArr[0]) |
| } |
| } |
| |
| func TestNamedQueryMap(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.Exec("drop table if exists PersistentUser") |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key") |
| table.ColMap("Key").Rename("mykey") |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| pu := &PersistentUser{43, "33r", false} |
| pu2 := &PersistentUser{500, "abc", false} |
| err = dbmap.Insert(pu, pu2) |
| if err != nil { |
| panic(err) |
| } |
| |
| // Test simple case |
| var puArr []*PersistentUser |
| _, err = dbmap.Select(&puArr, "select * from PersistentUser where mykey = :Key", map[string]interface{}{ |
| "Key": 43, |
| }) |
| if err != nil { |
| t.Errorf("Failed to select: %s", err) |
| t.FailNow() |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu, puArr[0]) { |
| t.Errorf("%v!=%v", pu, puArr[0]) |
| } |
| |
| // Test more specific map value type is ok |
| puArr = nil |
| _, err = dbmap.Select(&puArr, "select * from PersistentUser where mykey = :Key", map[string]int{ |
| "Key": 43, |
| }) |
| if err != nil { |
| t.Errorf("Failed to select: %s", err) |
| t.FailNow() |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| |
| // Test multiple parameters set. |
| puArr = nil |
| _, err = dbmap.Select(&puArr, ` |
| select * from PersistentUser |
| where mykey = :Key |
| and PassedTraining = :PassedTraining |
| and Id = :Id`, map[string]interface{}{ |
| "Key": 43, |
| "PassedTraining": false, |
| "Id": "33r", |
| }) |
| if err != nil { |
| t.Errorf("Failed to select: %s", err) |
| t.FailNow() |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| |
| // Test colon within a non-key string |
| // Test having extra, unused properties in the map. |
| puArr = nil |
| _, err = dbmap.Select(&puArr, ` |
| select * from PersistentUser |
| where mykey = :Key |
| and Id != 'abc:def'`, map[string]interface{}{ |
| "Key": 43, |
| "PassedTraining": false, |
| }) |
| if err != nil { |
| t.Errorf("Failed to select: %s", err) |
| t.FailNow() |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| |
| // Test to delete with Exec and named params. |
| result, err := dbmap.Exec("delete from PersistentUser where mykey = :Key", map[string]interface{}{ |
| "Key": 43, |
| }) |
| count, err := result.RowsAffected() |
| if err != nil { |
| t.Errorf("Failed to exec: %s", err) |
| t.FailNow() |
| } |
| if count != 1 { |
| t.Errorf("Expected 1 persistentuser to be deleted, but %d deleted", count) |
| } |
| } |
| |
| func TestNamedQueryStruct(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.Exec("drop table if exists PersistentUser") |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key") |
| table.ColMap("Key").Rename("mykey") |
| err := dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| pu := &PersistentUser{43, "33r", false} |
| pu2 := &PersistentUser{500, "abc", false} |
| err = dbmap.Insert(pu, pu2) |
| if err != nil { |
| panic(err) |
| } |
| |
| // Test select self |
| var puArr []*PersistentUser |
| _, err = dbmap.Select(&puArr, ` |
| select * from PersistentUser |
| where mykey = :Key |
| and PassedTraining = :PassedTraining |
| and Id = :Id`, pu) |
| if err != nil { |
| t.Errorf("Failed to select: %s", err) |
| t.FailNow() |
| } |
| if len(puArr) != 1 { |
| t.Errorf("Expected one persistentuser, found none") |
| } |
| if !reflect.DeepEqual(pu, puArr[0]) { |
| t.Errorf("%v!=%v", pu, puArr[0]) |
| } |
| |
| // Test delete self. |
| result, err := dbmap.Exec(` |
| delete from PersistentUser |
| where mykey = :Key |
| and PassedTraining = :PassedTraining |
| and Id = :Id`, pu) |
| count, err := result.RowsAffected() |
| if err != nil { |
| t.Errorf("Failed to exec: %s", err) |
| t.FailNow() |
| } |
| if count != 1 { |
| t.Errorf("Expected 1 persistentuser to be deleted, but %d deleted", count) |
| } |
| } |
| |
| // Ensure that the slices containing SQL results are non-nil when the result set is empty. |
| func TestReturnsNonNilSlice(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| noResultsSQL := "select * from invoice_test where id=99999" |
| var r1 []*Invoice |
| _rawselect(dbmap, &r1, noResultsSQL) |
| if r1 == nil { |
| t.Errorf("r1==nil") |
| } |
| |
| r2 := _rawselect(dbmap, Invoice{}, noResultsSQL) |
| if r2 == nil { |
| t.Errorf("r2==nil") |
| } |
| } |
| |
| func TestOverrideVersionCol(t *testing.T) { |
| dbmap := newDbMap() |
| t1 := dbmap.AddTable(InvoicePersonView{}).SetKeys(false, "InvoiceId", "PersonId") |
| err := dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| c1 := t1.SetVersionCol("LegacyVersion") |
| if c1.ColumnName != "LegacyVersion" { |
| t.Errorf("Wrong col returned: %v", c1) |
| } |
| |
| ipv := &InvoicePersonView{1, 2, "memo", "fname", 0} |
| _update(dbmap, ipv) |
| if ipv.LegacyVersion != 1 { |
| t.Errorf("LegacyVersion not updated: %d", ipv.LegacyVersion) |
| } |
| } |
| |
| func TestOptimisticLocking(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &Person{0, 0, 0, "Bob", "Smith", 0} |
| dbmap.Insert(p1) // Version is now 1 |
| if p1.Version != 1 { |
| t.Errorf("Insert didn't incr Version: %d != %d", 1, p1.Version) |
| return |
| } |
| if p1.Id == 0 { |
| t.Errorf("Insert didn't return a generated PK") |
| return |
| } |
| |
| obj, err := dbmap.Get(Person{}, p1.Id) |
| if err != nil { |
| panic(err) |
| } |
| p2 := obj.(*Person) |
| p2.LName = "Edwards" |
| dbmap.Update(p2) // Version is now 2 |
| if p2.Version != 2 { |
| t.Errorf("Update didn't incr Version: %d != %d", 2, p2.Version) |
| } |
| |
| p1.LName = "Howard" |
| count, err := dbmap.Update(p1) |
| if _, ok := err.(OptimisticLockError); !ok { |
| t.Errorf("update - Expected OptimisticLockError, got: %v", err) |
| } |
| if count != -1 { |
| t.Errorf("update - Expected -1 count, got: %d", count) |
| } |
| |
| count, err = dbmap.Delete(p1) |
| if _, ok := err.(OptimisticLockError); !ok { |
| t.Errorf("delete - Expected OptimisticLockError, got: %v", err) |
| } |
| if count != -1 { |
| t.Errorf("delete - Expected -1 count, got: %d", count) |
| } |
| } |
| |
| // what happens if a legacy table has a null value? |
| func TestDoubleAddTable(t *testing.T) { |
| dbmap := newDbMap() |
| t1 := dbmap.AddTable(TableWithNull{}).SetKeys(false, "Id") |
| t2 := dbmap.AddTable(TableWithNull{}) |
| if t1 != t2 { |
| t.Errorf("%v != %v", t1, t2) |
| } |
| } |
| |
| // what happens if a legacy table has a null value? |
| func TestNullValues(t *testing.T) { |
| dbmap := initDbMapNulls() |
| defer dropAndClose(dbmap) |
| |
| // insert a row directly |
| _rawexec(dbmap, "insert into TableWithNull values (10, null, "+ |
| "null, null, null, null)") |
| |
| // try to load it |
| expected := &TableWithNull{Id: 10} |
| obj := _get(dbmap, TableWithNull{}, 10) |
| t1 := obj.(*TableWithNull) |
| if !reflect.DeepEqual(expected, t1) { |
| t.Errorf("%v != %v", expected, t1) |
| } |
| |
| // update it |
| t1.Str = sql.NullString{"hi", true} |
| expected.Str = t1.Str |
| t1.Int64 = sql.NullInt64{999, true} |
| expected.Int64 = t1.Int64 |
| t1.Float64 = sql.NullFloat64{53.33, true} |
| expected.Float64 = t1.Float64 |
| t1.Bool = sql.NullBool{true, true} |
| expected.Bool = t1.Bool |
| t1.Bytes = []byte{1, 30, 31, 33} |
| expected.Bytes = t1.Bytes |
| _update(dbmap, t1) |
| |
| obj = _get(dbmap, TableWithNull{}, 10) |
| t1 = obj.(*TableWithNull) |
| if t1.Str.String != "hi" { |
| t.Errorf("%s != hi", t1.Str.String) |
| } |
| if !reflect.DeepEqual(expected, t1) { |
| t.Errorf("%v != %v", expected, t1) |
| } |
| } |
| |
| func TestColumnProps(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| t1 := dbmap.AddTable(Invoice{}).SetKeys(true, "Id") |
| t1.ColMap("Created").Rename("date_created") |
| t1.ColMap("Updated").SetTransient(true) |
| t1.ColMap("Memo").SetMaxSize(10) |
| t1.ColMap("PersonId").SetUnique(true) |
| |
| err := dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| defer dropAndClose(dbmap) |
| |
| // test transient |
| inv := &Invoice{0, 0, 1, "my invoice", 0, true} |
| _insert(dbmap, inv) |
| obj := _get(dbmap, Invoice{}, inv.Id) |
| inv = obj.(*Invoice) |
| if inv.Updated != 0 { |
| t.Errorf("Saved transient column 'Updated'") |
| } |
| |
| // test max size |
| inv.Memo = "this memo is too long" |
| err = dbmap.Insert(inv) |
| if err == nil { |
| t.Errorf("max size exceeded, but Insert did not fail.") |
| } |
| |
| // test unique - same person id |
| inv = &Invoice{0, 0, 1, "my invoice2", 0, false} |
| err = dbmap.Insert(inv) |
| if err == nil { |
| t.Errorf("same PersonId inserted, but Insert did not fail.") |
| } |
| } |
| |
| func TestRawSelect(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| _insert(dbmap, p1) |
| |
| inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id, true} |
| _insert(dbmap, inv1) |
| |
| expected := &InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName, 0} |
| |
| query := "select i.Id InvoiceId, p.Id PersonId, i.Memo, p.FName " + |
| "from invoice_test i, person_test p " + |
| "where i.PersonId = p.Id" |
| list := _rawselect(dbmap, InvoicePersonView{}, query) |
| if len(list) != 1 { |
| t.Errorf("len(list) != 1: %d", len(list)) |
| } else if !reflect.DeepEqual(expected, list[0]) { |
| t.Errorf("%v != %v", expected, list[0]) |
| } |
| } |
| |
| func TestHooks(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| _insert(dbmap, p1) |
| if p1.Created == 0 || p1.Updated == 0 { |
| t.Errorf("p1.PreInsert() didn't run: %v", p1) |
| } else if p1.LName != "postinsert" { |
| t.Errorf("p1.PostInsert() didn't run: %v", p1) |
| } |
| |
| obj := _get(dbmap, Person{}, p1.Id) |
| p1 = obj.(*Person) |
| if p1.LName != "postget" { |
| t.Errorf("p1.PostGet() didn't run: %v", p1) |
| } |
| |
| _update(dbmap, p1) |
| if p1.FName != "preupdate" { |
| t.Errorf("p1.PreUpdate() didn't run: %v", p1) |
| } else if p1.LName != "postupdate" { |
| t.Errorf("p1.PostUpdate() didn't run: %v", p1) |
| } |
| |
| var persons []*Person |
| bindVar := dbmap.Dialect.BindVar(0) |
| _rawselect(dbmap, &persons, "select * from person_test where id = "+bindVar, p1.Id) |
| if persons[0].LName != "postget" { |
| t.Errorf("p1.PostGet() didn't run after select: %v", p1) |
| } |
| |
| _del(dbmap, p1) |
| if p1.FName != "predelete" { |
| t.Errorf("p1.PreDelete() didn't run: %v", p1) |
| } else if p1.LName != "postdelete" { |
| t.Errorf("p1.PostDelete() didn't run: %v", p1) |
| } |
| |
| // Test error case |
| p2 := &Person{0, 0, 0, "badname", "", 0} |
| err := dbmap.Insert(p2) |
| if err == nil { |
| t.Errorf("p2.PreInsert() didn't return an error") |
| } |
| } |
| |
| func TestTransaction(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| inv1 := &Invoice{0, 100, 200, "t1", 0, true} |
| inv2 := &Invoice{0, 100, 200, "t2", 0, false} |
| |
| trans, err := dbmap.Begin() |
| if err != nil { |
| panic(err) |
| } |
| trans.Insert(inv1, inv2) |
| err = trans.Commit() |
| if err != nil { |
| panic(err) |
| } |
| |
| obj, err := dbmap.Get(Invoice{}, inv1.Id) |
| if err != nil { |
| panic(err) |
| } |
| if !reflect.DeepEqual(inv1, obj) { |
| t.Errorf("%v != %v", inv1, obj) |
| } |
| obj, err = dbmap.Get(Invoice{}, inv2.Id) |
| if err != nil { |
| panic(err) |
| } |
| if !reflect.DeepEqual(inv2, obj) { |
| t.Errorf("%v != %v", inv2, obj) |
| } |
| } |
| |
| func TestSavepoint(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| inv1 := &Invoice{0, 100, 200, "unpaid", 0, false} |
| |
| trans, err := dbmap.Begin() |
| if err != nil { |
| panic(err) |
| } |
| trans.Insert(inv1) |
| |
| var checkMemo = func(want string) { |
| memo, err := trans.SelectStr("select memo from invoice_test") |
| if err != nil { |
| panic(err) |
| } |
| if memo != want { |
| t.Errorf("%q != %q", want, memo) |
| } |
| } |
| checkMemo("unpaid") |
| |
| err = trans.Savepoint("foo") |
| if err != nil { |
| panic(err) |
| } |
| checkMemo("unpaid") |
| |
| inv1.Memo = "paid" |
| _, err = trans.Update(inv1) |
| if err != nil { |
| panic(err) |
| } |
| checkMemo("paid") |
| |
| err = trans.RollbackToSavepoint("foo") |
| if err != nil { |
| panic(err) |
| } |
| checkMemo("unpaid") |
| |
| err = trans.Rollback() |
| if err != nil { |
| panic(err) |
| } |
| } |
| |
| func TestMultiple(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| inv1 := &Invoice{0, 100, 200, "a", 0, false} |
| inv2 := &Invoice{0, 100, 200, "b", 0, true} |
| _insert(dbmap, inv1, inv2) |
| |
| inv1.Memo = "c" |
| inv2.Memo = "d" |
| _update(dbmap, inv1, inv2) |
| |
| count := _del(dbmap, inv1, inv2) |
| if count != 2 { |
| t.Errorf("%d != 2", count) |
| } |
| } |
| |
| func TestCrud(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| inv := &Invoice{0, 100, 200, "first order", 0, true} |
| testCrudInternal(t, dbmap, inv) |
| |
| invtag := &InvoiceTag{0, 300, 400, "some order", 33, false} |
| testCrudInternal(t, dbmap, invtag) |
| |
| foo := &AliasTransientField{BarStr: "some bar"} |
| testCrudInternal(t, dbmap, foo) |
| } |
| |
| func testCrudInternal(t *testing.T, dbmap *DbMap, val testable) { |
| table, _, err := dbmap.tableForPointer(val, false) |
| if err != nil { |
| t.Errorf("couldn't call TableFor: val=%v err=%v", val, err) |
| } |
| |
| _, err = dbmap.Exec("delete from " + table.TableName) |
| if err != nil { |
| t.Errorf("couldn't delete rows from: val=%v err=%v", val, err) |
| } |
| |
| // INSERT row |
| _insert(dbmap, val) |
| if val.GetId() == 0 { |
| t.Errorf("val.GetId() was not set on INSERT") |
| return |
| } |
| |
| // SELECT row |
| val2 := _get(dbmap, val, val.GetId()) |
| if !reflect.DeepEqual(val, val2) { |
| t.Errorf("%v != %v", val, val2) |
| } |
| |
| // UPDATE row and SELECT |
| val.Rand() |
| count := _update(dbmap, val) |
| if count != 1 { |
| t.Errorf("update 1 != %d", count) |
| } |
| val2 = _get(dbmap, val, val.GetId()) |
| if !reflect.DeepEqual(val, val2) { |
| t.Errorf("%v != %v", val, val2) |
| } |
| |
| // Select * |
| rows, err := dbmap.Select(val, "select * from "+table.TableName) |
| if err != nil { |
| t.Errorf("couldn't select * from %s err=%v", table.TableName, err) |
| } else if len(rows) != 1 { |
| t.Errorf("unexpected row count in %s: %d", table.TableName, len(rows)) |
| } else if !reflect.DeepEqual(val, rows[0]) { |
| t.Errorf("select * result: %v != %v", val, rows[0]) |
| } |
| |
| // DELETE row |
| deleted := _del(dbmap, val) |
| if deleted != 1 { |
| t.Errorf("Did not delete row with Id: %d", val.GetId()) |
| return |
| } |
| |
| // VERIFY deleted |
| val2 = _get(dbmap, val, val.GetId()) |
| if val2 != nil { |
| t.Errorf("Found invoice with id: %d after Delete()", val.GetId()) |
| } |
| } |
| |
| func TestWithIgnoredColumn(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| ic := &WithIgnoredColumn{-1, 0, 1} |
| _insert(dbmap, ic) |
| expected := &WithIgnoredColumn{0, 1, 1} |
| ic2 := _get(dbmap, WithIgnoredColumn{}, ic.Id).(*WithIgnoredColumn) |
| |
| if !reflect.DeepEqual(expected, ic2) { |
| t.Errorf("%v != %v", expected, ic2) |
| } |
| if _del(dbmap, ic) != 1 { |
| t.Errorf("Did not delete row with Id: %d", ic.Id) |
| return |
| } |
| if _get(dbmap, WithIgnoredColumn{}, ic.Id) != nil { |
| t.Errorf("Found id: %d after Delete()", ic.Id) |
| } |
| } |
| |
| func TestTypeConversionExample(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p := Person{FName: "Bob", LName: "Smith"} |
| tc := &TypeConversionExample{-1, p, CustomStringType("hi")} |
| _insert(dbmap, tc) |
| |
| expected := &TypeConversionExample{1, p, CustomStringType("hi")} |
| tc2 := _get(dbmap, TypeConversionExample{}, tc.Id).(*TypeConversionExample) |
| if !reflect.DeepEqual(expected, tc2) { |
| t.Errorf("tc2 %v != %v", expected, tc2) |
| } |
| |
| tc2.Name = CustomStringType("hi2") |
| tc2.PersonJSON = Person{FName: "Jane", LName: "Doe"} |
| _update(dbmap, tc2) |
| |
| expected = &TypeConversionExample{1, tc2.PersonJSON, CustomStringType("hi2")} |
| tc3 := _get(dbmap, TypeConversionExample{}, tc.Id).(*TypeConversionExample) |
| if !reflect.DeepEqual(expected, tc3) { |
| t.Errorf("tc3 %v != %v", expected, tc3) |
| } |
| |
| if _del(dbmap, tc) != 1 { |
| t.Errorf("Did not delete row with Id: %d", tc.Id) |
| } |
| |
| } |
| |
| func TestWithEmbeddedStruct(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| es := &WithEmbeddedStruct{-1, Names{FirstName: "Alice", LastName: "Smith"}} |
| _insert(dbmap, es) |
| expected := &WithEmbeddedStruct{1, Names{FirstName: "Alice", LastName: "Smith"}} |
| es2 := _get(dbmap, WithEmbeddedStruct{}, es.Id).(*WithEmbeddedStruct) |
| if !reflect.DeepEqual(expected, es2) { |
| t.Errorf("%v != %v", expected, es2) |
| } |
| |
| es2.FirstName = "Bob" |
| expected.FirstName = "Bob" |
| _update(dbmap, es2) |
| es2 = _get(dbmap, WithEmbeddedStruct{}, es.Id).(*WithEmbeddedStruct) |
| if !reflect.DeepEqual(expected, es2) { |
| t.Errorf("%v != %v", expected, es2) |
| } |
| |
| ess := _rawselect(dbmap, WithEmbeddedStruct{}, "select * from embedded_struct_test") |
| if !reflect.DeepEqual(es2, ess[0]) { |
| t.Errorf("%v != %v", es2, ess[0]) |
| } |
| } |
| |
| func TestWithEmbeddedStructBeforeAutoincr(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| esba := &WithEmbeddedStructBeforeAutoincrField{Names: Names{FirstName: "Alice", LastName: "Smith"}} |
| _insert(dbmap, esba) |
| var expectedAutoincrId int64 = 1 |
| if esba.Id != expectedAutoincrId { |
| t.Errorf("%d != %d", expectedAutoincrId, esba.Id) |
| } |
| } |
| |
| func TestWithEmbeddedAutoincr(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| esa := &WithEmbeddedAutoincr{ |
| WithEmbeddedStruct: WithEmbeddedStruct{Names: Names{FirstName: "Alice", LastName: "Smith"}}, |
| MiddleName: "Rose", |
| } |
| _insert(dbmap, esa) |
| var expectedAutoincrId int64 = 1 |
| if esa.Id != expectedAutoincrId { |
| t.Errorf("%d != %d", expectedAutoincrId, esa.Id) |
| } |
| } |
| |
| func TestSelectVal(t *testing.T) { |
| dbmap := initDbMapNulls() |
| defer dropAndClose(dbmap) |
| |
| bindVar := dbmap.Dialect.BindVar(0) |
| |
| t1 := TableWithNull{Str: sql.NullString{"abc", true}, |
| Int64: sql.NullInt64{78, true}, |
| Float64: sql.NullFloat64{32.2, true}, |
| Bool: sql.NullBool{true, true}, |
| Bytes: []byte("hi")} |
| _insert(dbmap, &t1) |
| |
| // SelectInt |
| i64 := selectInt(dbmap, "select Int64 from TableWithNull where Str='abc'") |
| if i64 != 78 { |
| t.Errorf("int64 %d != 78", i64) |
| } |
| i64 = selectInt(dbmap, "select count(*) from TableWithNull") |
| if i64 != 1 { |
| t.Errorf("int64 count %d != 1", i64) |
| } |
| i64 = selectInt(dbmap, "select count(*) from TableWithNull where Str="+bindVar, "asdfasdf") |
| if i64 != 0 { |
| t.Errorf("int64 no rows %d != 0", i64) |
| } |
| |
| // SelectNullInt |
| n := selectNullInt(dbmap, "select Int64 from TableWithNull where Str='notfound'") |
| if !reflect.DeepEqual(n, sql.NullInt64{0, false}) { |
| t.Errorf("nullint %v != 0,false", n) |
| } |
| |
| n = selectNullInt(dbmap, "select Int64 from TableWithNull where Str='abc'") |
| if !reflect.DeepEqual(n, sql.NullInt64{78, true}) { |
| t.Errorf("nullint %v != 78, true", n) |
| } |
| |
| // SelectFloat |
| f64 := selectFloat(dbmap, "select Float64 from TableWithNull where Str='abc'") |
| if f64 != 32.2 { |
| t.Errorf("float64 %d != 32.2", f64) |
| } |
| f64 = selectFloat(dbmap, "select min(Float64) from TableWithNull") |
| if f64 != 32.2 { |
| t.Errorf("float64 min %d != 32.2", f64) |
| } |
| f64 = selectFloat(dbmap, "select count(*) from TableWithNull where Str="+bindVar, "asdfasdf") |
| if f64 != 0 { |
| t.Errorf("float64 no rows %d != 0", f64) |
| } |
| |
| // SelectNullFloat |
| nf := selectNullFloat(dbmap, "select Float64 from TableWithNull where Str='notfound'") |
| if !reflect.DeepEqual(nf, sql.NullFloat64{0, false}) { |
| t.Errorf("nullfloat %v != 0,false", nf) |
| } |
| |
| nf = selectNullFloat(dbmap, "select Float64 from TableWithNull where Str='abc'") |
| if !reflect.DeepEqual(nf, sql.NullFloat64{32.2, true}) { |
| t.Errorf("nullfloat %v != 32.2, true", nf) |
| } |
| |
| // SelectStr |
| s := selectStr(dbmap, "select Str from TableWithNull where Int64="+bindVar, 78) |
| if s != "abc" { |
| t.Errorf("s %s != abc", s) |
| } |
| s = selectStr(dbmap, "select Str from TableWithNull where Str='asdfasdf'") |
| if s != "" { |
| t.Errorf("s no rows %s != ''", s) |
| } |
| |
| // SelectNullStr |
| ns := selectNullStr(dbmap, "select Str from TableWithNull where Int64="+bindVar, 78) |
| if !reflect.DeepEqual(ns, sql.NullString{"abc", true}) { |
| t.Errorf("nullstr %v != abc,true", ns) |
| } |
| ns = selectNullStr(dbmap, "select Str from TableWithNull where Str='asdfasdf'") |
| if !reflect.DeepEqual(ns, sql.NullString{"", false}) { |
| t.Errorf("nullstr no rows %v != '',false", ns) |
| } |
| |
| // SelectInt/Str with named parameters |
| i64 = selectInt(dbmap, "select Int64 from TableWithNull where Str=:abc", map[string]string{"abc": "abc"}) |
| if i64 != 78 { |
| t.Errorf("int64 %d != 78", i64) |
| } |
| ns = selectNullStr(dbmap, "select Str from TableWithNull where Int64=:num", map[string]int{"num": 78}) |
| if !reflect.DeepEqual(ns, sql.NullString{"abc", true}) { |
| t.Errorf("nullstr %v != abc,true", ns) |
| } |
| } |
| |
| func TestVersionMultipleRows(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| persons := []*Person{ |
| &Person{0, 0, 0, "Bob", "Smith", 0}, |
| &Person{0, 0, 0, "Jane", "Smith", 0}, |
| &Person{0, 0, 0, "Mike", "Smith", 0}, |
| } |
| |
| _insert(dbmap, persons[0], persons[1], persons[2]) |
| |
| for x, p := range persons { |
| if p.Version != 1 { |
| t.Errorf("person[%d].Version != 1: %d", x, p.Version) |
| } |
| } |
| } |
| |
| func TestWithStringPk(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTableWithName(WithStringPk{}, "string_pk_test").SetKeys(true, "Id") |
| _, err := dbmap.Exec("create table string_pk_test (Id varchar(255), Name varchar(255));") |
| if err != nil { |
| t.Errorf("couldn't create string_pk_test: %v", err) |
| } |
| defer dropAndClose(dbmap) |
| |
| row := &WithStringPk{"1", "foo"} |
| err = dbmap.Insert(row) |
| if err == nil { |
| t.Errorf("Expected error when inserting into table w/non Int PK and autoincr set true") |
| } |
| } |
| |
| // TestSqlExecutorInterfaceSelects ensures that all DbMap methods starting with Select... |
| // are also exposed in the SqlExecutor interface. Select... functions can always |
| // run on Pre/Post hooks. |
| func TestSqlExecutorInterfaceSelects(t *testing.T) { |
| dbMapType := reflect.TypeOf(&DbMap{}) |
| sqlExecutorType := reflect.TypeOf((*SqlExecutor)(nil)).Elem() |
| numDbMapMethods := dbMapType.NumMethod() |
| for i := 0; i < numDbMapMethods; i += 1 { |
| dbMapMethod := dbMapType.Method(i) |
| if !strings.HasPrefix(dbMapMethod.Name, "Select") { |
| continue |
| } |
| if _, found := sqlExecutorType.MethodByName(dbMapMethod.Name); !found { |
| t.Errorf("Method %s is defined on DbMap but not implemented in SqlExecutor", |
| dbMapMethod.Name) |
| } |
| } |
| } |
| |
| func TestNullTime(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| // if time is null |
| ent := &WithNullTime{ |
| Id: 0, |
| Time: NullTime{ |
| Valid: false, |
| }} |
| err := dbmap.Insert(ent) |
| if err != nil { |
| t.Error("failed insert on %s", err.Error()) |
| } |
| err = dbmap.SelectOne(ent, `select * from nulltime_test where Id=:Id`, map[string]interface{}{ |
| "Id": ent.Id, |
| }) |
| if err != nil { |
| t.Error("failed select on %s", err.Error()) |
| } |
| if ent.Time.Valid { |
| t.Error("NullTime returns valid but expected null.") |
| } |
| |
| // if time is not null |
| ts, err := time.Parse(time.Stamp, "Jan 2 15:04:05") |
| ent = &WithNullTime{ |
| Id: 1, |
| Time: NullTime{ |
| Valid: true, |
| Time: ts, |
| }} |
| err = dbmap.Insert(ent) |
| if err != nil { |
| t.Error("failed insert on %s", err.Error()) |
| } |
| err = dbmap.SelectOne(ent, `select * from nulltime_test where Id=:Id`, map[string]interface{}{ |
| "Id": ent.Id, |
| }) |
| if err != nil { |
| t.Error("failed select on %s", err.Error()) |
| } |
| if !ent.Time.Valid { |
| t.Error("NullTime returns invalid but expected valid.") |
| } |
| if ent.Time.Time.UTC() != ts.UTC() { |
| t.Errorf("expect %v but got %v.", ts, ent.Time.Time) |
| } |
| |
| return |
| } |
| |
| type WithTime struct { |
| Id int64 |
| Time time.Time |
| } |
| |
| type Times struct { |
| One time.Time |
| Two time.Time |
| } |
| |
| type EmbeddedTime struct { |
| Id string |
| Times |
| } |
| |
| func parseTimeOrPanic(format, date string) time.Time { |
| t1, err := time.Parse(format, date) |
| if err != nil { |
| panic(err) |
| } |
| return t1 |
| } |
| |
| // TODO: re-enable next two tests when this is merged: |
| // https://github.com/ziutek/mymysql/pull/77 |
| // |
| // This test currently fails w/MySQL b/c tz info is lost |
| func testWithTime(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| t1 := parseTimeOrPanic("2006-01-02 15:04:05 -0700 MST", |
| "2013-08-09 21:30:43 +0800 CST") |
| w1 := WithTime{1, t1} |
| _insert(dbmap, &w1) |
| |
| obj := _get(dbmap, WithTime{}, w1.Id) |
| w2 := obj.(*WithTime) |
| if w1.Time.UnixNano() != w2.Time.UnixNano() { |
| t.Errorf("%v != %v", w1, w2) |
| } |
| } |
| |
| // See: https://github.com/go-gorp/gorp/issues/86 |
| func testEmbeddedTime(t *testing.T) { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTable(EmbeddedTime{}).SetKeys(false, "Id") |
| defer dropAndClose(dbmap) |
| err := dbmap.CreateTables() |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| time1 := parseTimeOrPanic("2006-01-02 15:04:05", "2013-08-09 21:30:43") |
| |
| t1 := &EmbeddedTime{Id: "abc", Times: Times{One: time1, Two: time1.Add(10 * time.Second)}} |
| _insert(dbmap, t1) |
| |
| x := _get(dbmap, EmbeddedTime{}, t1.Id) |
| t2, _ := x.(*EmbeddedTime) |
| if t1.One.UnixNano() != t2.One.UnixNano() || t1.Two.UnixNano() != t2.Two.UnixNano() { |
| t.Errorf("%v != %v", t1, t2) |
| } |
| } |
| |
| func TestWithTimeSelect(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| halfhourago := time.Now().UTC().Add(-30 * time.Minute) |
| |
| w1 := WithTime{1, halfhourago.Add(time.Minute * -1)} |
| w2 := WithTime{2, halfhourago.Add(time.Second)} |
| _insert(dbmap, &w1, &w2) |
| |
| var caseIds []int64 |
| _, err := dbmap.Select(&caseIds, "SELECT id FROM time_test WHERE Time < "+dbmap.Dialect.BindVar(0), halfhourago) |
| |
| if err != nil { |
| t.Error(err) |
| } |
| if len(caseIds) != 1 { |
| t.Errorf("%d != 1", len(caseIds)) |
| } |
| if caseIds[0] != w1.Id { |
| t.Errorf("%d != %d", caseIds[0], w1.Id) |
| } |
| } |
| |
| func TestInvoicePersonView(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| // Create some rows |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| dbmap.Insert(p1) |
| |
| // notice how we can wire up p1.Id to the invoice easily |
| inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id, false} |
| dbmap.Insert(inv1) |
| |
| // Run your query |
| query := "select i.Id InvoiceId, p.Id PersonId, i.Memo, p.FName " + |
| "from invoice_test i, person_test p " + |
| "where i.PersonId = p.Id" |
| |
| // pass a slice of pointers to Select() |
| // this avoids the need to type assert after the query is run |
| var list []*InvoicePersonView |
| _, err := dbmap.Select(&list, query) |
| if err != nil { |
| panic(err) |
| } |
| |
| // this should test true |
| expected := &InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName, 0} |
| if !reflect.DeepEqual(list[0], expected) { |
| t.Errorf("%v != %v", list[0], expected) |
| } |
| } |
| |
| func TestQuoteTableNames(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| quotedTableName := dbmap.Dialect.QuoteField("person_test") |
| |
| // Use a buffer to hold the log to check generated queries |
| logBuffer := &bytes.Buffer{} |
| dbmap.TraceOn("", log.New(logBuffer, "gorptest:", log.Lmicroseconds)) |
| |
| // Create some rows |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| errorTemplate := "Expected quoted table name %v in query but didn't find it" |
| |
| // Check if Insert quotes the table name |
| id := dbmap.Insert(p1) |
| if !bytes.Contains(logBuffer.Bytes(), []byte(quotedTableName)) { |
| t.Errorf(errorTemplate, quotedTableName) |
| } |
| logBuffer.Reset() |
| |
| // Check if Get quotes the table name |
| dbmap.Get(Person{}, id) |
| if !bytes.Contains(logBuffer.Bytes(), []byte(quotedTableName)) { |
| t.Errorf(errorTemplate, quotedTableName) |
| } |
| logBuffer.Reset() |
| } |
| |
| func TestSelectTooManyCols(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| p2 := &Person{0, 0, 0, "jane", "doe", 0} |
| _insert(dbmap, p1) |
| _insert(dbmap, p2) |
| |
| obj := _get(dbmap, Person{}, p1.Id) |
| p1 = obj.(*Person) |
| obj = _get(dbmap, Person{}, p2.Id) |
| p2 = obj.(*Person) |
| |
| params := map[string]interface{}{ |
| "Id": p1.Id, |
| } |
| |
| var p3 FNameOnly |
| err := dbmap.SelectOne(&p3, "select * from person_test where Id=:Id", params) |
| if err != nil { |
| if !NonFatalError(err) { |
| t.Error(err) |
| } |
| } else { |
| t.Errorf("Non-fatal error expected") |
| } |
| |
| if p1.FName != p3.FName { |
| t.Errorf("%v != %v", p1.FName, p3.FName) |
| } |
| |
| var pSlice []FNameOnly |
| _, err = dbmap.Select(&pSlice, "select * from person_test order by fname asc") |
| if err != nil { |
| if !NonFatalError(err) { |
| t.Error(err) |
| } |
| } else { |
| t.Errorf("Non-fatal error expected") |
| } |
| |
| if p1.FName != pSlice[0].FName { |
| t.Errorf("%v != %v", p1.FName, pSlice[0].FName) |
| } |
| if p2.FName != pSlice[1].FName { |
| t.Errorf("%v != %v", p2.FName, pSlice[1].FName) |
| } |
| } |
| |
| func TestSelectSingleVal(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &Person{0, 0, 0, "bob", "smith", 0} |
| _insert(dbmap, p1) |
| |
| obj := _get(dbmap, Person{}, p1.Id) |
| p1 = obj.(*Person) |
| |
| params := map[string]interface{}{ |
| "Id": p1.Id, |
| } |
| |
| var p2 Person |
| err := dbmap.SelectOne(&p2, "select * from person_test where Id=:Id", params) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| if !reflect.DeepEqual(p1, &p2) { |
| t.Errorf("%v != %v", p1, &p2) |
| } |
| |
| // verify SelectOne allows non-struct holders |
| var s string |
| err = dbmap.SelectOne(&s, "select FName from person_test where Id=:Id", params) |
| if err != nil { |
| t.Error(err) |
| } |
| if s != "bob" { |
| t.Error("Expected bob but got: " + s) |
| } |
| |
| // verify SelectOne requires pointer receiver |
| err = dbmap.SelectOne(s, "select FName from person_test where Id=:Id", params) |
| if err == nil { |
| t.Error("SelectOne should have returned error for non-pointer holder") |
| } |
| |
| // verify SelectOne works with uninitialized pointers |
| var p3 *Person |
| err = dbmap.SelectOne(&p3, "select * from person_test where Id=:Id", params) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| if !reflect.DeepEqual(p1, p3) { |
| t.Errorf("%v != %v", p1, p3) |
| } |
| |
| // verify that the receiver is still nil if nothing was found |
| var p4 *Person |
| dbmap.SelectOne(&p3, "select * from person_test where 2<1 AND Id=:Id", params) |
| if p4 != nil { |
| t.Error("SelectOne should not have changed a nil receiver when no rows were found") |
| } |
| |
| // verify that the error is set to sql.ErrNoRows if not found |
| err = dbmap.SelectOne(&p2, "select * from person_test where Id=:Id", map[string]interface{}{ |
| "Id": -2222, |
| }) |
| if err == nil || err != sql.ErrNoRows { |
| t.Error("SelectOne should have returned an sql.ErrNoRows") |
| } |
| |
| _insert(dbmap, &Person{0, 0, 0, "bob", "smith", 0}) |
| err = dbmap.SelectOne(&p2, "select * from person_test where Fname='bob'") |
| if err == nil { |
| t.Error("Expected error when two rows found") |
| } |
| |
| // tests for #150 |
| var tInt int64 |
| var tStr string |
| var tBool bool |
| var tFloat float64 |
| primVals := []interface{}{tInt, tStr, tBool, tFloat} |
| for _, prim := range primVals { |
| err = dbmap.SelectOne(&prim, "select * from person_test where Id=-123") |
| if err == nil || err != sql.ErrNoRows { |
| t.Error("primVals: SelectOne should have returned sql.ErrNoRows") |
| } |
| } |
| } |
| |
| func TestSelectAlias(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| p1 := &IdCreatedExternal{IdCreated: IdCreated{Id: 1, Created: 3}, External: 2} |
| |
| // Insert using embedded IdCreated, which reflects the structure of the table |
| _insert(dbmap, &p1.IdCreated) |
| |
| // Select into IdCreatedExternal type, which includes some fields not present |
| // in id_created_test |
| var p2 IdCreatedExternal |
| err := dbmap.SelectOne(&p2, "select * from id_created_test where Id=1") |
| if err != nil { |
| t.Error(err) |
| } |
| if p2.Id != 1 || p2.Created != 3 || p2.External != 0 { |
| t.Error("Expected ignored field defaults to not set") |
| } |
| |
| // Prove that we can supply an aliased value in the select, and that it will |
| // automatically map to IdCreatedExternal.External |
| err = dbmap.SelectOne(&p2, "SELECT *, 1 AS external FROM id_created_test") |
| if err != nil { |
| t.Error(err) |
| } |
| if p2.External != 1 { |
| t.Error("Expected select as can map to exported field.") |
| } |
| |
| var rows *sql.Rows |
| var cols []string |
| rows, err = dbmap.Db.Query("SELECT * FROM id_created_test") |
| cols, err = rows.Columns() |
| if err != nil || len(cols) != 2 { |
| t.Error("Expected ignored column not created") |
| } |
| } |
| |
| func TestMysqlPanicIfDialectNotInitialized(t *testing.T) { |
| _, driver := dialectAndDriver() |
| // this test only applies to MySQL |
| if os.Getenv("GORP_TEST_DIALECT") != "mysql" { |
| return |
| } |
| |
| // The expected behaviour is to catch a panic. |
| // Here is the deferred function which will check if a panic has indeed occurred : |
| defer func() { |
| r := recover() |
| if r == nil { |
| t.Error("db.CreateTables() should panic if db is initialized with an incorrect MySQLDialect") |
| } |
| }() |
| |
| // invalid MySQLDialect : does not contain Engine or Encoding specification |
| dialect := MySQLDialect{} |
| db := &DbMap{Db: connect(driver), Dialect: dialect} |
| db.AddTableWithName(Invoice{}, "invoice") |
| // the following call should panic : |
| db.CreateTables() |
| } |
| |
| func TestSingleColumnKeyDbReturnsZeroRowsUpdatedOnPKChange(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| dbmap.AddTableWithName(SingleColumnTable{}, "single_column_table").SetKeys(false, "SomeId") |
| err := dbmap.DropTablesIfExists() |
| if err != nil { |
| t.Error("Drop tables failed") |
| } |
| err = dbmap.CreateTablesIfNotExists() |
| if err != nil { |
| t.Error("Create tables failed") |
| } |
| err = dbmap.TruncateTables() |
| if err != nil { |
| t.Error("Truncate tables failed") |
| } |
| |
| sct := SingleColumnTable{ |
| SomeId: "A Unique Id String", |
| } |
| |
| count, err := dbmap.Update(&sct) |
| if err != nil { |
| t.Error(err) |
| } |
| if count != 0 { |
| t.Errorf("Expected 0 updated rows, got %d", count) |
| } |
| |
| } |
| |
| func TestPrepare(t *testing.T) { |
| dbmap := initDbMap() |
| defer dropAndClose(dbmap) |
| |
| inv1 := &Invoice{0, 100, 200, "prepare-foo", 0, false} |
| inv2 := &Invoice{0, 100, 200, "prepare-bar", 0, false} |
| _insert(dbmap, inv1, inv2) |
| |
| bindVar0 := dbmap.Dialect.BindVar(0) |
| bindVar1 := dbmap.Dialect.BindVar(1) |
| stmt, err := dbmap.Prepare(fmt.Sprintf("UPDATE invoice_test SET Memo=%s WHERE Id=%s", bindVar0, bindVar1)) |
| if err != nil { |
| t.Error(err) |
| } |
| defer stmt.Close() |
| _, err = stmt.Exec("prepare-baz", inv1.Id) |
| if err != nil { |
| t.Error(err) |
| } |
| err = dbmap.SelectOne(inv1, "SELECT * from invoice_test WHERE Memo='prepare-baz'") |
| if err != nil { |
| t.Error(err) |
| } |
| |
| trans, err := dbmap.Begin() |
| if err != nil { |
| t.Error(err) |
| } |
| transStmt, err := trans.Prepare(fmt.Sprintf("UPDATE invoice_test SET IsPaid=%s WHERE Id=%s", bindVar0, bindVar1)) |
| if err != nil { |
| t.Error(err) |
| } |
| defer transStmt.Close() |
| _, err = transStmt.Exec(true, inv2.Id) |
| if err != nil { |
| t.Error(err) |
| } |
| err = dbmap.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE IsPaid=%s", bindVar0), true) |
| if err == nil || err != sql.ErrNoRows { |
| t.Error("SelectOne should have returned an sql.ErrNoRows") |
| } |
| err = trans.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE IsPaid=%s", bindVar0), true) |
| if err != nil { |
| t.Error(err) |
| } |
| err = trans.Commit() |
| if err != nil { |
| t.Error(err) |
| } |
| err = dbmap.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE IsPaid=%s", bindVar0), true) |
| if err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func BenchmarkNativeCrud(b *testing.B) { |
| b.StopTimer() |
| dbmap := initDbMapBench() |
| defer dropAndClose(dbmap) |
| b.StartTimer() |
| |
| insert := "insert into invoice_test (Created, Updated, Memo, PersonId) values (?, ?, ?, ?)" |
| sel := "select Id, Created, Updated, Memo, PersonId from invoice_test where Id=?" |
| update := "update invoice_test set Created=?, Updated=?, Memo=?, PersonId=? where Id=?" |
| delete := "delete from invoice_test where Id=?" |
| |
| inv := &Invoice{0, 100, 200, "my memo", 0, false} |
| |
| for i := 0; i < b.N; i++ { |
| res, err := dbmap.Db.Exec(insert, inv.Created, inv.Updated, |
| inv.Memo, inv.PersonId) |
| if err != nil { |
| panic(err) |
| } |
| |
| newid, err := res.LastInsertId() |
| if err != nil { |
| panic(err) |
| } |
| inv.Id = newid |
| |
| row := dbmap.Db.QueryRow(sel, inv.Id) |
| err = row.Scan(&inv.Id, &inv.Created, &inv.Updated, &inv.Memo, |
| &inv.PersonId) |
| if err != nil { |
| panic(err) |
| } |
| |
| inv.Created = 1000 |
| inv.Updated = 2000 |
| inv.Memo = "my memo 2" |
| inv.PersonId = 3000 |
| |
| _, err = dbmap.Db.Exec(update, inv.Created, inv.Updated, inv.Memo, |
| inv.PersonId, inv.Id) |
| if err != nil { |
| panic(err) |
| } |
| |
| _, err = dbmap.Db.Exec(delete, inv.Id) |
| if err != nil { |
| panic(err) |
| } |
| } |
| |
| } |
| |
| func BenchmarkGorpCrud(b *testing.B) { |
| b.StopTimer() |
| dbmap := initDbMapBench() |
| defer dropAndClose(dbmap) |
| b.StartTimer() |
| |
| inv := &Invoice{0, 100, 200, "my memo", 0, true} |
| for i := 0; i < b.N; i++ { |
| err := dbmap.Insert(inv) |
| if err != nil { |
| panic(err) |
| } |
| |
| obj, err := dbmap.Get(Invoice{}, inv.Id) |
| if err != nil { |
| panic(err) |
| } |
| |
| inv2, ok := obj.(*Invoice) |
| if !ok { |
| panic(fmt.Sprintf("expected *Invoice, got: %v", obj)) |
| } |
| |
| inv2.Created = 1000 |
| inv2.Updated = 2000 |
| inv2.Memo = "my memo 2" |
| inv2.PersonId = 3000 |
| _, err = dbmap.Update(inv2) |
| if err != nil { |
| panic(err) |
| } |
| |
| _, err = dbmap.Delete(inv2) |
| if err != nil { |
| panic(err) |
| } |
| |
| } |
| } |
| |
| func initDbMapBench() *DbMap { |
| dbmap := newDbMap() |
| dbmap.Db.Exec("drop table if exists invoice_test") |
| dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id") |
| err := dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| return dbmap |
| } |
| |
| func initDbMap() *DbMap { |
| dbmap := newDbMap() |
| dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(InvoiceTag{}, "invoice_tag_test").SetKeys(true, "myid") |
| dbmap.AddTableWithName(AliasTransientField{}, "alias_trans_field_test").SetKeys(true, "id") |
| dbmap.AddTableWithName(OverriddenInvoice{}, "invoice_override_test").SetKeys(false, "Id") |
| dbmap.AddTableWithName(Person{}, "person_test").SetKeys(true, "Id").SetVersionCol("Version") |
| dbmap.AddTableWithName(WithIgnoredColumn{}, "ignored_column_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(IdCreated{}, "id_created_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(TypeConversionExample{}, "type_conv_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(WithEmbeddedStruct{}, "embedded_struct_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(WithEmbeddedStructBeforeAutoincrField{}, "embedded_struct_before_autoincr_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(WithEmbeddedAutoincr{}, "embedded_autoincr_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(WithTime{}, "time_test").SetKeys(true, "Id") |
| dbmap.AddTableWithName(WithNullTime{}, "nulltime_test").SetKeys(false, "Id") |
| dbmap.TypeConverter = testTypeConverter{} |
| err := dbmap.DropTablesIfExists() |
| if err != nil { |
| panic(err) |
| } |
| err = dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| |
| // See #146 and TestSelectAlias - this type is mapped to the same |
| // table as IdCreated, but includes an extra field that isn't in the table |
| dbmap.AddTableWithName(IdCreatedExternal{}, "id_created_test").SetKeys(true, "Id") |
| |
| return dbmap |
| } |
| |
| func initDbMapNulls() *DbMap { |
| dbmap := newDbMap() |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| dbmap.AddTable(TableWithNull{}).SetKeys(false, "Id") |
| err := dbmap.CreateTables() |
| if err != nil { |
| panic(err) |
| } |
| return dbmap |
| } |
| |
| func newDbMap() *DbMap { |
| dialect, driver := dialectAndDriver() |
| dbmap := &DbMap{Db: connect(driver), Dialect: dialect} |
| dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds)) |
| return dbmap |
| } |
| |
| func dropAndClose(dbmap *DbMap) { |
| dbmap.DropTablesIfExists() |
| dbmap.Db.Close() |
| } |
| |
| func connect(driver string) *sql.DB { |
| dsn := os.Getenv("GORP_TEST_DSN") |
| if dsn == "" { |
| panic("GORP_TEST_DSN env variable is not set. Please see README.md") |
| } |
| |
| db, err := sql.Open(driver, dsn) |
| if err != nil { |
| panic("Error connecting to db: " + err.Error()) |
| } |
| return db |
| } |
| |
| func dialectAndDriver() (Dialect, string) { |
| switch os.Getenv("GORP_TEST_DIALECT") { |
| case "mysql": |
| return MySQLDialect{"InnoDB", "UTF8"}, "mymysql" |
| case "gomysql": |
| return MySQLDialect{"InnoDB", "UTF8"}, "mysql" |
| case "postgres": |
| return PostgresDialect{}, "postgres" |
| case "sqlite": |
| return SqliteDialect{}, "sqlite3" |
| } |
| panic("GORP_TEST_DIALECT env variable is not set or is invalid. Please see README.md") |
| } |
| |
| func _insert(dbmap *DbMap, list ...interface{}) { |
| err := dbmap.Insert(list...) |
| if err != nil { |
| panic(err) |
| } |
| } |
| |
| func _update(dbmap *DbMap, list ...interface{}) int64 { |
| count, err := dbmap.Update(list...) |
| if err != nil { |
| panic(err) |
| } |
| return count |
| } |
| |
| func _del(dbmap *DbMap, list ...interface{}) int64 { |
| count, err := dbmap.Delete(list...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return count |
| } |
| |
| func _get(dbmap *DbMap, i interface{}, keys ...interface{}) interface{} { |
| obj, err := dbmap.Get(i, keys...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return obj |
| } |
| |
| func selectInt(dbmap *DbMap, query string, args ...interface{}) int64 { |
| i64, err := SelectInt(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return i64 |
| } |
| |
| func selectNullInt(dbmap *DbMap, query string, args ...interface{}) sql.NullInt64 { |
| i64, err := SelectNullInt(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return i64 |
| } |
| |
| func selectFloat(dbmap *DbMap, query string, args ...interface{}) float64 { |
| f64, err := SelectFloat(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return f64 |
| } |
| |
| func selectNullFloat(dbmap *DbMap, query string, args ...interface{}) sql.NullFloat64 { |
| f64, err := SelectNullFloat(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return f64 |
| } |
| |
| func selectStr(dbmap *DbMap, query string, args ...interface{}) string { |
| s, err := SelectStr(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return s |
| } |
| |
| func selectNullStr(dbmap *DbMap, query string, args ...interface{}) sql.NullString { |
| s, err := SelectNullStr(dbmap, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| |
| return s |
| } |
| |
| func _rawexec(dbmap *DbMap, query string, args ...interface{}) sql.Result { |
| res, err := dbmap.Exec(query, args...) |
| if err != nil { |
| panic(err) |
| } |
| return res |
| } |
| |
| func _rawselect(dbmap *DbMap, i interface{}, query string, args ...interface{}) []interface{} { |
| list, err := dbmap.Select(i, query, args...) |
| if err != nil { |
| panic(err) |
| } |
| return list |
| } |