From 4473ab9228379c12b6431e3de13b0ede3c50dba9 Mon Sep 17 00:00:00 2001 From: xormplus Date: Sat, 3 Jun 2017 06:06:07 +0800 Subject: [PATCH] add some tests --- cache_lru.go | 294 +++++++++++ cache_memory_store.go | 51 ++ cache_test.go | 148 ++++++ helpler_time.go | 21 + processors_test.go | 966 ++++++++++++++++++++++++++++++++++++ rows_test.go | 41 ++ session_cols_test.go | 25 +- session_cond_test.go | 167 +++++++ session_delete_test.go | 125 +++++ session_find_test.go | 407 +++++++++++++++ session_get_test.go | 47 ++ session_insert_test.go | 475 ++++++++++++++++++ session_iterate_test.go | 38 ++ session_pk_test.go | 12 + session_raw_test.go | 26 + session_schema_test.go | 218 ++++++++ session_sum_test.go | 29 ++ session_tx_test.go | 192 ++++++++ session_update_test.go | 1037 ++++++++++++++++++++++++++++++++++++++- statement_test.go | 2 +- tag_cache_test.go | 39 ++ tag_extends_test.go | 538 ++++++++++++++++++++ tag_id_test.go | 85 ++++ tag_test.go | 189 +++++++ tag_version_test.go | 128 +++++ time_test.go | 476 ++++++++++++++++++ types_null_test.go | 404 +++++++++++++++ types_test.go | 238 +++++++++ xorm_test.go | 40 +- 29 files changed, 6435 insertions(+), 23 deletions(-) create mode 100644 cache_lru.go create mode 100644 cache_memory_store.go create mode 100644 cache_test.go create mode 100644 helpler_time.go create mode 100644 processors_test.go create mode 100644 rows_test.go create mode 100644 session_delete_test.go create mode 100644 session_iterate_test.go create mode 100644 session_schema_test.go create mode 100644 session_tx_test.go create mode 100644 tag_cache_test.go create mode 100644 tag_extends_test.go create mode 100644 tag_id_test.go create mode 100644 tag_test.go create mode 100644 tag_version_test.go create mode 100644 time_test.go create mode 100644 types_null_test.go diff --git a/cache_lru.go b/cache_lru.go new file mode 100644 index 0000000..eb20ce3 --- /dev/null +++ b/cache_lru.go @@ -0,0 +1,294 @@ +// Copyright 2015 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "container/list" + "fmt" + "sync" + "time" + + "github.com/xormplus/core" +) + +// LRUCacher implments cache object facilities +type LRUCacher struct { + idList *list.List + sqlList *list.List + idIndex map[string]map[string]*list.Element + sqlIndex map[string]map[string]*list.Element + store core.CacheStore + mutex sync.Mutex + // maxSize int + MaxElementSize int + Expired time.Duration + GcInterval time.Duration +} + +// NewLRUCacher creates a cacher +func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher { + return NewLRUCacher2(store, 3600*time.Second, maxElementSize) +} + +// NewLRUCacher2 creates a cache include different params +func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher { + cacher := &LRUCacher{store: store, idList: list.New(), + sqlList: list.New(), Expired: expired, + GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize, + sqlIndex: make(map[string]map[string]*list.Element), + idIndex: make(map[string]map[string]*list.Element), + } + cacher.RunGC() + return cacher +} + +// RunGC run once every m.GcInterval +func (m *LRUCacher) RunGC() { + time.AfterFunc(m.GcInterval, func() { + m.RunGC() + m.GC() + }) +} + +// GC check ids lit and sql list to remove all element expired +func (m *LRUCacher) GC() { + //fmt.Println("begin gc ...") + //defer fmt.Println("end gc ...") + m.mutex.Lock() + defer m.mutex.Unlock() + var removedNum int + for e := m.idList.Front(); e != nil; { + if removedNum <= core.CacheGcMaxRemoved && + time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { + removedNum++ + next := e.Next() + //fmt.Println("removing ...", e.Value) + node := e.Value.(*idNode) + m.delBean(node.tbName, node.id) + e = next + } else { + //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len()) + break + } + } + + removedNum = 0 + for e := m.sqlList.Front(); e != nil; { + if removedNum <= core.CacheGcMaxRemoved && + time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { + removedNum++ + next := e.Next() + //fmt.Println("removing ...", e.Value) + node := e.Value.(*sqlNode) + m.delIds(node.tbName, node.sql) + e = next + } else { + //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len()) + break + } + } +} + +// GetIds returns all bean's ids according to sql and parameter from cache +func (m *LRUCacher) GetIds(tableName, sql string) interface{} { + m.mutex.Lock() + defer m.mutex.Unlock() + if _, ok := m.sqlIndex[tableName]; !ok { + m.sqlIndex[tableName] = make(map[string]*list.Element) + } + if v, err := m.store.Get(sql); err == nil { + if el, ok := m.sqlIndex[tableName][sql]; !ok { + el = m.sqlList.PushBack(newSQLNode(tableName, sql)) + m.sqlIndex[tableName][sql] = el + } else { + lastTime := el.Value.(*sqlNode).lastVisit + // if expired, remove the node and return nil + if time.Now().Sub(lastTime) > m.Expired { + m.delIds(tableName, sql) + return nil + } + m.sqlList.MoveToBack(el) + el.Value.(*sqlNode).lastVisit = time.Now() + } + return v + } + + m.delIds(tableName, sql) + + return nil +} + +// GetBean returns bean according tableName and id from cache +func (m *LRUCacher) GetBean(tableName string, id string) interface{} { + m.mutex.Lock() + defer m.mutex.Unlock() + if _, ok := m.idIndex[tableName]; !ok { + m.idIndex[tableName] = make(map[string]*list.Element) + } + tid := genID(tableName, id) + if v, err := m.store.Get(tid); err == nil { + if el, ok := m.idIndex[tableName][id]; ok { + lastTime := el.Value.(*idNode).lastVisit + // if expired, remove the node and return nil + if time.Now().Sub(lastTime) > m.Expired { + m.delBean(tableName, id) + //m.clearIds(tableName) + return nil + } + m.idList.MoveToBack(el) + el.Value.(*idNode).lastVisit = time.Now() + } else { + el = m.idList.PushBack(newIDNode(tableName, id)) + m.idIndex[tableName][id] = el + } + return v + } + + // store bean is not exist, then remove memory's index + m.delBean(tableName, id) + //m.clearIds(tableName) + return nil +} + +// clearIds clears all sql-ids mapping on table tableName from cache +func (m *LRUCacher) clearIds(tableName string) { + if tis, ok := m.sqlIndex[tableName]; ok { + for sql, v := range tis { + m.sqlList.Remove(v) + m.store.Del(sql) + } + } + m.sqlIndex[tableName] = make(map[string]*list.Element) +} + +// ClearIds clears all sql-ids mapping on table tableName from cache +func (m *LRUCacher) ClearIds(tableName string) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.clearIds(tableName) +} + +func (m *LRUCacher) clearBeans(tableName string) { + if tis, ok := m.idIndex[tableName]; ok { + for id, v := range tis { + m.idList.Remove(v) + tid := genID(tableName, id) + m.store.Del(tid) + } + } + m.idIndex[tableName] = make(map[string]*list.Element) +} + +// ClearBeans clears all beans in some table +func (m *LRUCacher) ClearBeans(tableName string) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.clearBeans(tableName) +} + +// PutIds pus ids into table +func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { + m.mutex.Lock() + defer m.mutex.Unlock() + if _, ok := m.sqlIndex[tableName]; !ok { + m.sqlIndex[tableName] = make(map[string]*list.Element) + } + if el, ok := m.sqlIndex[tableName][sql]; !ok { + el = m.sqlList.PushBack(newSQLNode(tableName, sql)) + m.sqlIndex[tableName][sql] = el + } else { + el.Value.(*sqlNode).lastVisit = time.Now() + } + m.store.Put(sql, ids) + if m.sqlList.Len() > m.MaxElementSize { + e := m.sqlList.Front() + node := e.Value.(*sqlNode) + m.delIds(node.tbName, node.sql) + } +} + +// PutBean puts beans into table +func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { + m.mutex.Lock() + defer m.mutex.Unlock() + var el *list.Element + var ok bool + + if el, ok = m.idIndex[tableName][id]; !ok { + el = m.idList.PushBack(newIDNode(tableName, id)) + m.idIndex[tableName][id] = el + } else { + el.Value.(*idNode).lastVisit = time.Now() + } + + m.store.Put(genID(tableName, id), obj) + if m.idList.Len() > m.MaxElementSize { + e := m.idList.Front() + node := e.Value.(*idNode) + m.delBean(node.tbName, node.id) + } +} + +func (m *LRUCacher) delIds(tableName, sql string) { + if _, ok := m.sqlIndex[tableName]; ok { + if el, ok := m.sqlIndex[tableName][sql]; ok { + delete(m.sqlIndex[tableName], sql) + m.sqlList.Remove(el) + } + } + m.store.Del(sql) +} + +// DelIds deletes ids +func (m *LRUCacher) DelIds(tableName, sql string) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.delIds(tableName, sql) +} + +func (m *LRUCacher) delBean(tableName string, id string) { + tid := genID(tableName, id) + if el, ok := m.idIndex[tableName][id]; ok { + delete(m.idIndex[tableName], id) + m.idList.Remove(el) + m.clearIds(tableName) + } + m.store.Del(tid) +} + +// DelBean deletes beans in some table +func (m *LRUCacher) DelBean(tableName string, id string) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.delBean(tableName, id) +} + +type idNode struct { + tbName string + id string + lastVisit time.Time +} + +type sqlNode struct { + tbName string + sql string + lastVisit time.Time +} + +func genSQLKey(sql string, args interface{}) string { + return fmt.Sprintf("%v-%v", sql, args) +} + +func genID(prefix string, id string) string { + return fmt.Sprintf("%v-%v", prefix, id) +} + +func newIDNode(tbName string, id string) *idNode { + return &idNode{tbName, id, time.Now()} +} + +func newSQLNode(tbName, sql string) *sqlNode { + return &sqlNode{tbName, sql, time.Now()} +} diff --git a/cache_memory_store.go b/cache_memory_store.go new file mode 100644 index 0000000..b07898b --- /dev/null +++ b/cache_memory_store.go @@ -0,0 +1,51 @@ +// Copyright 2015 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "sync" + + "github.com/xormplus/core" +) + +var _ core.CacheStore = NewMemoryStore() + +// MemoryStore represents in-memory store +type MemoryStore struct { + store map[interface{}]interface{} + mutex sync.RWMutex +} + +// NewMemoryStore creates a new store in memory +func NewMemoryStore() *MemoryStore { + return &MemoryStore{store: make(map[interface{}]interface{})} +} + +// Put puts object into store +func (s *MemoryStore) Put(key string, value interface{}) error { + s.mutex.Lock() + defer s.mutex.Unlock() + s.store[key] = value + return nil +} + +// Get gets object from store +func (s *MemoryStore) Get(key string) (interface{}, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + if v, ok := s.store[key]; ok { + return v, nil + } + + return nil, ErrNotExist +} + +// Del deletes object +func (s *MemoryStore) Del(key string) error { + s.mutex.Lock() + defer s.mutex.Unlock() + delete(s.store, key) + return nil +} diff --git a/cache_test.go b/cache_test.go new file mode 100644 index 0000000..e867192 --- /dev/null +++ b/cache_test.go @@ -0,0 +1,148 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestCacheFind(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type MailBox struct { + Id int64 + Username string + Password string + } + + cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) + testEngine.SetDefaultCacher(cacher) + + assert.NoError(t, testEngine.Sync2(new(MailBox))) + + var inserts = []*MailBox{ + { + Username: "user1", + Password: "pass1", + }, + { + Username: "user2", + Password: "pass2", + }, + } + _, err := testEngine.Insert(inserts[0], inserts[1]) + assert.NoError(t, err) + + var boxes []MailBox + assert.NoError(t, testEngine.Find(&boxes)) + assert.EqualValues(t, 2, len(boxes)) + for i, box := range boxes { + assert.Equal(t, inserts[i].Id, box.Id) + assert.Equal(t, inserts[i].Username, box.Username) + assert.Equal(t, inserts[i].Password, box.Password) + } + + boxes = make([]MailBox, 0, 2) + assert.NoError(t, testEngine.Find(&boxes)) + assert.EqualValues(t, 2, len(boxes)) + for i, box := range boxes { + assert.Equal(t, inserts[i].Id, box.Id) + assert.Equal(t, inserts[i].Username, box.Username) + assert.Equal(t, inserts[i].Password, box.Password) + } + + testEngine.SetDefaultCacher(nil) +} + +func TestCacheFind2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type MailBox2 struct { + Id uint64 + Username string + Password string + } + + cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) + testEngine.SetDefaultCacher(cacher) + + assert.NoError(t, testEngine.Sync2(new(MailBox2))) + + var inserts = []*MailBox2{ + { + Username: "user1", + Password: "pass1", + }, + { + Username: "user2", + Password: "pass2", + }, + } + _, err := testEngine.Insert(inserts[0], inserts[1]) + assert.NoError(t, err) + + var boxes []MailBox2 + assert.NoError(t, testEngine.Find(&boxes)) + assert.EqualValues(t, 2, len(boxes)) + for i, box := range boxes { + assert.Equal(t, inserts[i].Id, box.Id) + assert.Equal(t, inserts[i].Username, box.Username) + assert.Equal(t, inserts[i].Password, box.Password) + } + + boxes = make([]MailBox2, 0, 2) + assert.NoError(t, testEngine.Find(&boxes)) + assert.EqualValues(t, 2, len(boxes)) + for i, box := range boxes { + assert.Equal(t, inserts[i].Id, box.Id) + assert.Equal(t, inserts[i].Username, box.Username) + assert.Equal(t, inserts[i].Password, box.Password) + } + + testEngine.SetDefaultCacher(nil) +} + +func TestCacheGet(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type MailBox3 struct { + Id uint64 + Username string + Password string + } + + cacher := NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) + testEngine.SetDefaultCacher(cacher) + + assert.NoError(t, testEngine.Sync2(new(MailBox3))) + + var inserts = []*MailBox3{ + { + Username: "user1", + Password: "pass1", + }, + } + _, err := testEngine.Insert(inserts[0]) + assert.NoError(t, err) + + var box1 MailBox3 + has, err := testEngine.Where("id = ?", inserts[0].Id).Get(&box1) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, "user1", box1.Username) + assert.EqualValues(t, "pass1", box1.Password) + + var box2 MailBox3 + has, err = testEngine.Where("id = ?", inserts[0].Id).Get(&box2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, "user1", box2.Username) + assert.EqualValues(t, "pass1", box2.Password) + + testEngine.SetDefaultCacher(nil) +} diff --git a/helpler_time.go b/helpler_time.go new file mode 100644 index 0000000..f4013e2 --- /dev/null +++ b/helpler_time.go @@ -0,0 +1,21 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import "time" + +const ( + zeroTime0 = "0000-00-00 00:00:00" + zeroTime1 = "0001-01-01 00:00:00" +) + +func formatTime(t time.Time) string { + return t.Format("2006-01-02 15:04:05") +} + +func isTimeZero(t time.Time) bool { + return t.IsZero() || formatTime(t) == zeroTime0 || + formatTime(t) == zeroTime1 +} diff --git a/processors_test.go b/processors_test.go new file mode 100644 index 0000000..6c22af0 --- /dev/null +++ b/processors_test.go @@ -0,0 +1,966 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBefore_Get(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type BeforeTable struct { + Id int64 + Name string + Val string `xorm:"-"` + } + + assert.NoError(t, testEngine.Sync2(new(BeforeTable))) + + cnt, err := testEngine.Insert(&BeforeTable{ + Name: "test", + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var be BeforeTable + has, err := testEngine.Before(func(bean interface{}) { + bean.(*BeforeTable).Val = "val" + }).Get(&be) + assert.NoError(t, err) + assert.Equal(t, true, has) + assert.Equal(t, "val", be.Val) + assert.Equal(t, "test", be.Name) +} + +func TestBefore_Find(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type BeforeTable struct { + Id int64 + Name string + Val string `xorm:"-"` + } + + assert.NoError(t, testEngine.Sync2(new(BeforeTable))) + + cnt, err := testEngine.Insert([]BeforeTable{ + {Name: "test1"}, + {Name: "test2"}, + }) + assert.NoError(t, err) + assert.EqualValues(t, 2, cnt) + + var be []BeforeTable + err = testEngine.Before(func(bean interface{}) { + bean.(*BeforeTable).Val = "val" + }).Find(&be) + assert.NoError(t, err) + assert.Equal(t, 2, len(be)) + assert.Equal(t, "val", be[0].Val) + assert.Equal(t, "test1", be[0].Name) + assert.Equal(t, "val", be[1].Val) + assert.Equal(t, "test2", be[1].Name) +} + +type ProcessorsStruct struct { + Id int64 + + B4InsertFlag int + AfterInsertedFlag int + B4UpdateFlag int + AfterUpdatedFlag int + B4DeleteFlag int `xorm:"-"` + AfterDeletedFlag int `xorm:"-"` + BeforeSetFlag int `xorm:"-"` + + B4InsertViaExt int + AfterInsertedViaExt int + B4UpdateViaExt int + AfterUpdatedViaExt int + B4DeleteViaExt int `xorm:"-"` + AfterDeletedViaExt int `xorm:"-"` + AfterSetFlag int `xorm:"-"` +} + +func (p *ProcessorsStruct) BeforeInsert() { + p.B4InsertFlag = 1 +} + +func (p *ProcessorsStruct) BeforeUpdate() { + p.B4UpdateFlag = 1 +} + +func (p *ProcessorsStruct) BeforeDelete() { + p.B4DeleteFlag = 1 +} + +func (p *ProcessorsStruct) BeforeSet(col string, cell Cell) { + p.BeforeSetFlag = p.BeforeSetFlag + 1 +} + +func (p *ProcessorsStruct) AfterInsert() { + p.AfterInsertedFlag = 1 +} + +func (p *ProcessorsStruct) AfterUpdate() { + p.AfterUpdatedFlag = 1 +} + +func (p *ProcessorsStruct) AfterDelete() { + p.AfterDeletedFlag = 1 +} + +func (p *ProcessorsStruct) AfterSet(col string, cell Cell) { + p.AfterSetFlag = p.AfterSetFlag + 1 +} + +func TestProcessors(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&ProcessorsStruct{}) + if err != nil { + t.Error(err) + panic(err) + } + p := &ProcessorsStruct{} + + err = testEngine.CreateTables(&ProcessorsStruct{}) + if err != nil { + t.Error(err) + panic(err) + } + + b4InsertFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4InsertViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterInsertFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterInsertedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + _, err = testEngine.Before(b4InsertFunc).After(afterInsertFunc).Insert(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedViaExt == 0 { + t.Error(errors.New("AfterInsertedViaExt not set")) + } + } + + p2 := &ProcessorsStruct{} + _, err = testEngine.Id(p.Id).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p2.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p2.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p2.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + if p2.BeforeSetFlag != 9 { + t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p2.BeforeSetFlag)) + } + if p2.AfterSetFlag != 9 { + t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p2.BeforeSetFlag)) + } + } + // -- + + // test find processors + var p2Find []*ProcessorsStruct + err = testEngine.Find(&p2Find) + if err != nil { + t.Error(err) + panic(err) + } else { + if len(p2Find) != 1 { + err = errors.New("Should get 1") + t.Error(err) + } + p21 := p2Find[0] + if p21.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p21.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p21.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p21.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + if p21.BeforeSetFlag != 9 { + t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p21.BeforeSetFlag)) + } + if p21.AfterSetFlag != 9 { + t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p21.BeforeSetFlag)) + } + } + // -- + + // test find map processors + var p2FindMap = make(map[int64]*ProcessorsStruct) + err = testEngine.Find(&p2FindMap) + if err != nil { + t.Error(err) + panic(err) + } else { + if len(p2FindMap) != 1 { + err = errors.New("Should get 1") + t.Error(err) + } + var p22 *ProcessorsStruct + for _, v := range p2FindMap { + p22 = v + } + + if p22.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p22.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p22.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p22.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + if p22.BeforeSetFlag != 9 { + t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p22.BeforeSetFlag)) + } + if p22.AfterSetFlag != 9 { + t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p22.BeforeSetFlag)) + } + } + // -- + + // test update processors + b4UpdateFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4UpdateViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterUpdateFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterUpdatedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + p = p2 // reset + + _, err = testEngine.Before(b4UpdateFunc).After(afterUpdateFunc).Update(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag == 0 { + t.Error(errors.New("AfterUpdatedFlag not set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt == 0 { + t.Error(errors.New("AfterUpdatedViaExt not set")) + } + } + + p2 = &ProcessorsStruct{} + _, err = testEngine.Id(p.Id).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p2.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set: " + string(p.AfterUpdatedFlag))) + } + if p2.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p2.AfterUpdatedViaExt != 0 { + t.Error(errors.New("AfterUpdatedViaExt is set: " + string(p.AfterUpdatedViaExt))) + } + if p2.BeforeSetFlag != 9 { + t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p2.BeforeSetFlag)) + } + if p2.AfterSetFlag != 9 { + t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p2.BeforeSetFlag)) + } + } + // -- + + // test delete processors + b4DeleteFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4DeleteViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterDeleteFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterDeletedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + p = p2 // reset + _, err = testEngine.Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag == 0 { + t.Error(errors.New("AfterDeletedFlag not set")) + } + if p.B4DeleteViaExt == 0 { + t.Error(errors.New("B4DeleteViaExt not set")) + } + if p.AfterDeletedViaExt == 0 { + t.Error(errors.New("AfterDeletedViaExt not set")) + } + } + // -- + + // test insert multi + pslice := make([]*ProcessorsStruct, 0) + pslice = append(pslice, &ProcessorsStruct{}) + pslice = append(pslice, &ProcessorsStruct{}) + cnt, err := testEngine.Before(b4InsertFunc).After(afterInsertFunc).Insert(&pslice) + if err != nil { + t.Error(err) + panic(err) + } else { + if cnt != 2 { + t.Error(errors.New("incorrect insert count")) + } + for _, elem := range pslice { + if elem.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if elem.AfterInsertedFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if elem.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if elem.AfterInsertedViaExt == 0 { + t.Error(errors.New("AfterInsertedViaExt not set")) + } + } + } + + for _, elem := range pslice { + p = &ProcessorsStruct{} + _, err = testEngine.Id(elem.Id).Get(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p2.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p2.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p2.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + if p2.BeforeSetFlag != 9 { + t.Error(fmt.Errorf("BeforeSetFlag is %d not 9", p2.BeforeSetFlag)) + } + if p2.AfterSetFlag != 9 { + t.Error(fmt.Errorf("AfterSetFlag is %d not 9", p2.BeforeSetFlag)) + } + } + } + // -- +} + +func TestProcessorsTx(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&ProcessorsStruct{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&ProcessorsStruct{}) + if err != nil { + t.Error(err) + panic(err) + } + + // test insert processors with tx rollback + session := testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p := &ProcessorsStruct{} + b4InsertFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4InsertViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterInsertFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterInsertedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + _, err = session.Before(b4InsertFunc).After(afterInsertFunc).Insert(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedFlag != 0 { + t.Error(errors.New("B4InsertFlag is set")) + } + if p.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + } + + err = session.Rollback() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedFlag != 0 { + t.Error(errors.New("B4InsertFlag is set")) + } + if p.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + } + session.Close() + p2 := &ProcessorsStruct{} + _, err = testEngine.Id(p.Id).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.Id > 0 { + err = errors.New("tx got committed upon insert!?") + t.Error(err) + panic(err) + } + } + // -- + + // test insert processors with tx commit + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p = &ProcessorsStruct{} + _, err = session.Before(b4InsertFunc).After(afterInsertFunc).Insert(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + } + + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p.AfterInsertedFlag == 0 { + t.Error(errors.New("AfterInsertedFlag not set")) + } + if p.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p.AfterInsertedViaExt == 0 { + t.Error(errors.New("AfterInsertedViaExt not set")) + } + } + session.Close() + p2 = &ProcessorsStruct{} + _, err = testEngine.Id(p.Id).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4InsertFlag == 0 { + t.Error(errors.New("B4InsertFlag not set")) + } + if p2.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag is set")) + } + if p2.B4InsertViaExt == 0 { + t.Error(errors.New("B4InsertViaExt not set")) + } + if p2.AfterInsertedViaExt != 0 { + t.Error(errors.New("AfterInsertedViaExt is set")) + } + } + insertedId := p2.Id + // -- + + // test update processors with tx rollback + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + b4UpdateFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4UpdateViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterUpdateFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterUpdatedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + p = p2 // reset + + _, err = session.Id(insertedId).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt != 0 { + t.Error(errors.New("AfterUpdatedViaExt is set")) + } + } + err = session.Rollback() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt != 0 { + t.Error(errors.New("AfterUpdatedViaExt is set")) + } + } + + session.Close() + + p2 = &ProcessorsStruct{} + _, err = testEngine.Id(insertedId).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4UpdateFlag != 0 { + t.Error(errors.New("B4UpdateFlag is set")) + } + if p2.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set")) + } + if p2.B4UpdateViaExt != 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p2.AfterUpdatedViaExt != 0 { + t.Error(errors.New("AfterUpdatedViaExt is set")) + } + } + // -- + + // test update processors with tx rollback + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p = &ProcessorsStruct{Id: insertedId} + + _, err = session.Update(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set")) + } + } + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag == 0 { + t.Error(errors.New("AfterUpdatedFlag not set")) + } + if p.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag set")) + } + if p.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag set")) + } + } + + session.Close() + + // test update processors with tx commit + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p = &ProcessorsStruct{} + + _, err = session.Id(insertedId).Before(b4UpdateFunc).After(afterUpdateFunc).Update(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag is set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt != 0 { + t.Error(errors.New("AfterUpdatedViaExt is set")) + } + } + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag == 0 { + t.Error(errors.New("AfterUpdatedFlag not set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt == 0 { + t.Error(errors.New("AfterUpdatedViaExt not set")) + } + } + session.Close() + p2 = &ProcessorsStruct{} + _, err = testEngine.Id(insertedId).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4UpdateFlag == 0 { + t.Error(errors.New("B4UpdateFlag not set")) + } + if p.AfterUpdatedFlag == 0 { + t.Error(errors.New("AfterUpdatedFlag not set")) + } + if p.B4UpdateViaExt == 0 { + t.Error(errors.New("B4UpdateViaExt not set")) + } + if p.AfterUpdatedViaExt == 0 { + t.Error(errors.New("AfterUpdatedViaExt not set")) + } + } + // -- + + // test delete processors with tx rollback + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + b4DeleteFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.B4DeleteViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + afterDeleteFunc := func(bean interface{}) { + if v, ok := (bean).(*ProcessorsStruct); ok { + v.AfterDeletedViaExt = 1 + } else { + t.Error(errors.New("cast to ProcessorsStruct failed, how can this be!?")) + } + } + + p = &ProcessorsStruct{} // reset + + _, err = session.Id(insertedId).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag is set")) + } + if p.B4DeleteViaExt == 0 { + t.Error(errors.New("B4DeleteViaExt not set")) + } + if p.AfterDeletedViaExt != 0 { + t.Error(errors.New("AfterDeletedViaExt is set")) + } + } + err = session.Rollback() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag is set")) + } + if p.B4DeleteViaExt == 0 { + t.Error(errors.New("B4DeleteViaExt not set")) + } + if p.AfterDeletedViaExt != 0 { + t.Error(errors.New("AfterDeletedViaExt is set")) + } + } + session.Close() + + p2 = &ProcessorsStruct{} + _, err = testEngine.Id(insertedId).Get(p2) + if err != nil { + t.Error(err) + panic(err) + } else { + if p2.B4DeleteFlag != 0 { + t.Error(errors.New("B4DeleteFlag is set")) + } + if p2.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag is set")) + } + if p2.B4DeleteViaExt != 0 { + t.Error(errors.New("B4DeleteViaExt is set")) + } + if p2.AfterDeletedViaExt != 0 { + t.Error(errors.New("AfterDeletedViaExt is set")) + } + } + // -- + + // test delete processors with tx commit + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p = &ProcessorsStruct{} + + _, err = session.Id(insertedId).Before(b4DeleteFunc).After(afterDeleteFunc).Delete(p) + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag is set")) + } + if p.B4DeleteViaExt == 0 { + t.Error(errors.New("B4DeleteViaExt not set")) + } + if p.AfterDeletedViaExt != 0 { + t.Error(errors.New("AfterDeletedViaExt is set")) + } + } + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag == 0 { + t.Error(errors.New("AfterDeletedFlag not set")) + } + if p.B4DeleteViaExt == 0 { + t.Error(errors.New("B4DeleteViaExt not set")) + } + if p.AfterDeletedViaExt == 0 { + t.Error(errors.New("AfterDeletedViaExt not set")) + } + } + session.Close() + + // test delete processors with tx commit + session = testEngine.NewSession() + err = session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + p = &ProcessorsStruct{Id: insertedId} + fmt.Println("delete") + _, err = session.Delete(p) + + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag != 0 { + t.Error(errors.New("AfterDeletedFlag is set")) + } + } + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } else { + if p.B4DeleteFlag == 0 { + t.Error(errors.New("B4DeleteFlag not set")) + } + if p.AfterDeletedFlag == 0 { + t.Error(errors.New("AfterDeletedFlag not set")) + } + if p.AfterInsertedFlag != 0 { + t.Error(errors.New("AfterInsertedFlag set")) + } + if p.AfterUpdatedFlag != 0 { + t.Error(errors.New("AfterUpdatedFlag set")) + } + } + session.Close() + // -- +} diff --git a/rows_test.go b/rows_test.go new file mode 100644 index 0000000..b246329 --- /dev/null +++ b/rows_test.go @@ -0,0 +1,41 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRows(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserRows struct { + Id int64 + IsMan bool + } + + assert.NoError(t, testEngine.Sync2(new(UserRows))) + + cnt, err := testEngine.Insert(&UserRows{ + IsMan: true, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + rows, err := testEngine.Rows(new(UserRows)) + assert.NoError(t, err) + defer rows.Close() + + cnt = 0 + user := new(UserRows) + for rows.Next() { + err = rows.Scan(user) + assert.NoError(t, err) + cnt++ + } + assert.EqualValues(t, 1, cnt) +} diff --git a/session_cols_test.go b/session_cols_test.go index 8bef8bd..a78e27a 100644 --- a/session_cols_test.go +++ b/session_cols_test.go @@ -4,13 +4,34 @@ package xorm -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/xormplus/core" +) func TestSetExpr(t *testing.T) { + assert.NoError(t, prepareEngine()) + type User struct { Id int64 Show bool } - testEngine.SetExpr("show", "NOT show").Id(1).Update(new(User)) + assert.NoError(t, testEngine.Sync2(new(User))) + + cnt, err := testEngine.Insert(&User{ + Show: true, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var not = "NOT" + if testEngine.dialect.DBType() == core.MSSQL { + not = "~" + } + cnt, err = testEngine.SetExpr("show", not+" `show`").Id(1).Update(new(User)) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) } diff --git a/session_cond_test.go b/session_cond_test.go index d5a9392..d90fbc2 100644 --- a/session_cond_test.go +++ b/session_cond_test.go @@ -5,6 +5,8 @@ package xorm import ( + "errors" + "fmt" "testing" "github.com/go-xorm/builder" @@ -93,3 +95,168 @@ func TestBuilder(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, len(conds), "records should exist") } + +func TestIn(t *testing.T) { + assert.NoError(t, prepareEngine()) + assert.NoError(t, testEngine.Sync2(new(Userinfo))) + + cnt, err := testEngine.Insert([]Userinfo{ + { + Username: "user1", + Departname: "dev", + }, + { + Username: "user2", + Departname: "dev", + }, + { + Username: "user3", + Departname: "dev", + }, + }) + assert.NoError(t, err) + assert.EqualValues(t, 3, cnt) + + var usrs []Userinfo + err = testEngine.Limit(3).Find(&usrs) + if err != nil { + t.Error(err) + panic(err) + } + + if len(usrs) != 3 { + err = errors.New("there are not 3 records") + t.Error(err) + panic(err) + } + + var ids []int64 + var idsStr string + for _, u := range usrs { + ids = append(ids, u.Uid) + idsStr = fmt.Sprintf("%d,", u.Uid) + } + idsStr = idsStr[:len(idsStr)-1] + + users := make([]Userinfo, 0) + err = testEngine.In("(id)", ids[0], ids[1], ids[2]).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + if len(users) != 3 { + err = errors.New("in uses should be " + idsStr + " total 3") + t.Error(err) + panic(err) + } + + users = make([]Userinfo, 0) + err = testEngine.In("(id)", ids).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + if len(users) != 3 { + err = errors.New("in uses should be " + idsStr + " total 3") + t.Error(err) + panic(err) + } + + for _, user := range users { + if user.Uid != ids[0] && user.Uid != ids[1] && user.Uid != ids[2] { + err = errors.New("in uses should be " + idsStr + " total 3") + t.Error(err) + panic(err) + } + } + + users = make([]Userinfo, 0) + var idsInterface []interface{} + for _, id := range ids { + idsInterface = append(idsInterface, id) + } + + department := "`" + testEngine.ColumnMapper.Obj2Table("Departname") + "`" + err = testEngine.Where(department+" = ?", "dev").In("(id)", idsInterface...).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + if len(users) != 3 { + err = errors.New("in uses should be " + idsStr + " total 3") + t.Error(err) + panic(err) + } + + for _, user := range users { + if user.Uid != ids[0] && user.Uid != ids[1] && user.Uid != ids[2] { + err = errors.New("in uses should be " + idsStr + " total 3") + t.Error(err) + panic(err) + } + } + + dev := testEngine.ColumnMapper.Obj2Table("Dev") + + err = testEngine.In("(id)", 1).In("(id)", 2).In(department, dev).Find(&users) + + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + cnt, err = testEngine.In("(id)", ids[0]).Update(&Userinfo{Departname: "dev-"}) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update records not 1") + t.Error(err) + panic(err) + } + + user := new(Userinfo) + has, err := testEngine.Id(ids[0]).Get(user) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("get record not 1") + t.Error(err) + panic(err) + } + if user.Departname != "dev-" { + err = errors.New("update not success") + t.Error(err) + panic(err) + } + + cnt, err = testEngine.In("(id)", ids[0]).Update(&Userinfo{Departname: "dev"}) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update records not 1") + t.Error(err) + panic(err) + } + + cnt, err = testEngine.In("(id)", ids[1]).Delete(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("deleted records not 1") + t.Error(err) + panic(err) + } +} diff --git a/session_delete_test.go b/session_delete_test.go new file mode 100644 index 0000000..6522a13 --- /dev/null +++ b/session_delete_test.go @@ -0,0 +1,125 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDelete(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserinfoDelete struct { + Uid int64 + IsMan bool + } + + assert.NoError(t, testEngine.Sync2(new(UserinfoDelete))) + + user := UserinfoDelete{Uid: 1} + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + cnt, err = testEngine.Delete(&UserinfoDelete{Uid: 1}) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + user.Uid = 0 + user.IsMan = true + has, err := testEngine.Id(1).Get(&user) + assert.NoError(t, err) + assert.False(t, has) +} + +func TestDeleted(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type Deleted struct { + Id int64 `xorm:"pk"` + Name string + DeletedAt time.Time `xorm:"deleted"` + } + + err := testEngine.DropTables(&Deleted{}) + assert.NoError(t, err) + + err = testEngine.CreateTables(&Deleted{}) + assert.NoError(t, err) + + _, err = testEngine.InsertOne(&Deleted{Id: 1, Name: "11111"}) + assert.NoError(t, err) + + _, err = testEngine.InsertOne(&Deleted{Id: 2, Name: "22222"}) + assert.NoError(t, err) + + _, err = testEngine.InsertOne(&Deleted{Id: 3, Name: "33333"}) + assert.NoError(t, err) + + // Test normal Find() + var records1 []Deleted + err = testEngine.Where("`"+testEngine.ColumnMapper.Obj2Table("Id")+"` > 0").Find(&records1, &Deleted{}) + assert.EqualValues(t, 3, len(records1)) + + // Test normal Get() + record1 := &Deleted{} + has, err := testEngine.Id(1).Get(record1) + assert.NoError(t, err) + assert.True(t, has) + + // Test Delete() with deleted + affected, err := testEngine.Id(1).Delete(&Deleted{}) + assert.NoError(t, err) + assert.EqualValues(t, 1, affected) + + has, err = testEngine.Id(1).Get(&Deleted{}) + assert.NoError(t, err) + assert.False(t, has) + + var records2 []Deleted + err = testEngine.Where("`" + testEngine.ColumnMapper.Obj2Table("Id") + "` > 0").Find(&records2) + assert.NoError(t, err) + assert.EqualValues(t, 2, len(records2)) + + // Test no rows affected after Delete() again. + affected, err = testEngine.Id(1).Delete(&Deleted{}) + assert.NoError(t, err) + assert.EqualValues(t, 0, affected) + + // Deleted.DeletedAt must not be updated. + affected, err = testEngine.Id(2).Update(&Deleted{Name: "2", DeletedAt: time.Now()}) + assert.NoError(t, err) + assert.EqualValues(t, 1, affected) + + record2 := &Deleted{} + has, err = testEngine.Id(2).Get(record2) + assert.NoError(t, err) + assert.True(t, record2.DeletedAt.IsZero()) + + // Test find all records whatever `deleted`. + var unscopedRecords1 []Deleted + err = testEngine.Unscoped().Where("`"+testEngine.ColumnMapper.Obj2Table("Id")+"` > 0").Find(&unscopedRecords1, &Deleted{}) + assert.NoError(t, err) + assert.EqualValues(t, 3, len(unscopedRecords1)) + + // Delete() must really delete a record with Unscoped() + affected, err = testEngine.Unscoped().Id(1).Delete(&Deleted{}) + assert.NoError(t, err) + assert.EqualValues(t, 1, affected) + + var unscopedRecords2 []Deleted + err = testEngine.Unscoped().Where("`"+testEngine.ColumnMapper.Obj2Table("Id")+"` > 0").Find(&unscopedRecords2, &Deleted{}) + assert.NoError(t, err) + assert.EqualValues(t, 2, len(unscopedRecords2)) + + var records3 []Deleted + err = testEngine.Where("`"+testEngine.ColumnMapper.Obj2Table("Id")+"` > 0").And("`"+testEngine.ColumnMapper.Obj2Table("Id")+"`> 1"). + Or("`"+testEngine.ColumnMapper.Obj2Table("Id")+"` = ?", 3).Find(&records3) + assert.NoError(t, err) + assert.EqualValues(t, 2, len(records3)) +} diff --git a/session_find_test.go b/session_find_test.go index ef60b68..b52fa76 100644 --- a/session_find_test.go +++ b/session_find_test.go @@ -5,9 +5,12 @@ package xorm import ( + "errors" + "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/xormplus/core" ) func TestJoinLimit(t *testing.T) { @@ -57,3 +60,407 @@ func TestJoinLimit(t *testing.T) { Find(&salaries) assert.NoError(t, err) } + +func assertSync(t *testing.T, beans ...interface{}) { + for _, bean := range beans { + assert.NoError(t, testEngine.DropTables(bean)) + assert.NoError(t, testEngine.Sync(bean)) + } +} + +func TestWhere(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.Where("(id) > ?", 2).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + err = testEngine.Where("(id) > ?", 2).And("(id) < ?", 10).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) +} + +func TestFind(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } + + users2 := make([]Userinfo, 0) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + err = testEngine.Sql("select * from " + testEngine.Quote(userinfo)).Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestFind2(t *testing.T) { + assert.NoError(t, prepareEngine()) + users := make([]*Userinfo, 0) + + assertSync(t, new(Userinfo)) + + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } +} + +type Team struct { + Id int64 +} + +type TeamUser struct { + OrgId int64 + Uid int64 + TeamId int64 +} + +func TestFind3(t *testing.T) { + assert.NoError(t, prepareEngine()) + err := testEngine.Sync2(new(Team), new(TeamUser)) + if err != nil { + t.Error(err) + panic(err.Error()) + } + + var teams []Team + err = testEngine.Cols("`team`.id"). + Where("`team_user`.org_id=?", 1). + And("`team_user`.uid=?", 2). + Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id"). + Find(&teams) + if err != nil { + t.Error(err) + panic(err.Error()) + } +} + +func TestFindMap(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make(map[int64]Userinfo) + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } +} + +func TestFindMap2(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make(map[int64]*Userinfo) + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for id, user := range users { + fmt.Println(id, user) + } +} + +func TestDistinct(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + _, err := testEngine.Insert(&Userinfo{ + Username: "lunny", + }) + assert.NoError(t, err) + + users := make([]Userinfo, 0) + departname := testEngine.TableMapper.Obj2Table("Departname") + err = testEngine.Distinct(departname).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + if len(users) != 1 { + t.Error(err) + panic(errors.New("should be one record")) + } + + fmt.Println(users) + + type Depart struct { + Departname string + } + + users2 := make([]Depart, 0) + err = testEngine.Distinct(departname).Table(new(Userinfo)).Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + if len(users2) != 1 { + t.Error(err) + panic(errors.New("should be one record")) + } + fmt.Println(users2) +} + +func TestOrder(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.OrderBy("id desc").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + users2 := make([]Userinfo, 0) + err = testEngine.Asc("id", "username").Desc("height").Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users2) +} + +func TestHaving(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.GroupBy("username").Having("username='xlw'").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + /*users = make([]Userinfo, 0) + err = testEngine.Cols("id, username").GroupBy("username").Having("username='xlw'").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users)*/ +} + +func TestOrderSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + testEngine.unMapType(rValue(new(Userinfo)).Type()) + + mapper := testEngine.TableMapper + testEngine.SetMapper(core.SameMapper{}) + + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(mapper) + }() + + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.OrderBy("(id) desc").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + users2 := make([]Userinfo, 0) + err = testEngine.Asc("(id)", "Username").Desc("Height").Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users2) +} + +func TestHavingSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + testEngine.unMapType(rValue(new(Userinfo)).Type()) + + mapper := testEngine.TableMapper + testEngine.SetMapper(core.SameMapper{}) + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(mapper) + }() + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.GroupBy("`Username`").Having("`Username`='xlw'").Find(&users) + if err != nil { + t.Fatal(err) + } + fmt.Println(users) +} + +func TestFindInts(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var idsInt64 []int64 + err := testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt64) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt64) + + var idsInt32 []int32 + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt32) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt32) + + var idsInt []int + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt) + + var idsUint []uint + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsUint) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsUint) + + type MyInt int + var idsMyInt []MyInt + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsMyInt) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsMyInt) +} + +func TestFindStrings(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + var idsString []string + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsString) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsString) +} + +func TestFindMyString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + + var idsMyString []MyString + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsMyString) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsMyString) +} + +func TestFindInterface(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + var idsInterface []interface{} + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsInterface) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInterface) +} + +func TestFindSliceBytes(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids [][][]byte + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindSlicePtrString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids [][]*string + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindMapBytes(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids []map[string][]byte + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindMapPtrString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids []map[string]*string + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} diff --git a/session_get_test.go b/session_get_test.go index ee6711a..916ccdd 100644 --- a/session_get_test.go +++ b/session_get_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/xormplus/core" ) func TestGetVar(t *testing.T) { @@ -108,3 +109,49 @@ func TestGetVar(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "1.5", fmt.Sprintf("%v", v4)) } + +func TestGetStruct(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserinfoGet struct { + Uid int `xorm:"pk autoincr"` + IsMan bool + } + + assert.NoError(t, testEngine.Sync(new(UserinfoGet))) + + var err error + if testEngine.dialect.DBType() == core.MSSQL { + _, err = testEngine.Exec("SET IDENTITY_INSERT userinfo_get ON") + assert.NoError(t, err) + } + cnt, err := testEngine.Insert(&UserinfoGet{Uid: 2}) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + user := UserinfoGet{Uid: 2} + has, err := testEngine.Get(&user) + assert.NoError(t, err) + assert.True(t, has) + + type NoIdUser struct { + User string `xorm:"unique"` + Remain int64 + Total int64 + } + + assert.NoError(t, testEngine.Sync(&NoIdUser{})) + + userCol := testEngine.ColumnMapper.Obj2Table("User") + _, err = testEngine.Where("`"+userCol+"` = ?", "xlw").Delete(&NoIdUser{}) + assert.NoError(t, err) + + cnt, err = testEngine.Insert(&NoIdUser{"xlw", 20, 100}) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + noIdUser := new(NoIdUser) + has, err = testEngine.Where("`"+userCol+"` = ?", "xlw").Get(noIdUser) + assert.NoError(t, err) + assert.True(t, has) +} diff --git a/session_insert_test.go b/session_insert_test.go index 288b4b7..2163755 100644 --- a/session_insert_test.go +++ b/session_insert_test.go @@ -5,6 +5,7 @@ package xorm import ( + "errors" "fmt" "reflect" "testing" @@ -152,3 +153,477 @@ func TestInsertOneIfPkIsPointRename(t *testing.T) { _, err := testEngine.InsertOne(&data) assert.NoError(t, err) } + +func TestInsert(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + user := Userinfo{0, "xiaolunwen", "dev", "lunny", time.Now(), + Userdetail{Id: 1}, 1.78, []byte{1, 2, 3}, true} + cnt, err := testEngine.Insert(&user) + fmt.Println(user.Uid) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + } + + if user.Uid <= 0 { + err = errors.New("not return id error") + t.Error(err) + panic(err) + } + + user.Uid = 0 + cnt, err = testEngine.Insert(&user) + if err == nil { + err = errors.New("insert failed but no return error") + t.Error(err) + panic(err) + } + if cnt != 0 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } +} + +func TestInsertAutoIncr(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assertSync(t, new(Userinfo)) + + // auto increment insert + user := Userinfo{Username: "xiaolunwen2", Departname: "dev", Alias: "lunny", Created: time.Now(), + Detail: Userdetail{Id: 1}, Height: 1.78, Avatar: []byte{1, 2, 3}, IsMan: true} + cnt, err := testEngine.Insert(&user) + fmt.Println(user.Uid) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + } + if user.Uid <= 0 { + t.Error(errors.New("not return id error")) + } +} + +type DefaultInsert struct { + Id int64 + Status int `xorm:"default -1"` + Name string + Created time.Time `xorm:"created"` + Updated time.Time `xorm:"updated"` +} + +func TestInsertDefault(t *testing.T) { + assert.NoError(t, prepareEngine()) + + di := new(DefaultInsert) + err := testEngine.Sync2(di) + if err != nil { + t.Error(err) + } + + var di2 = DefaultInsert{Name: "test"} + _, err = testEngine.Omit(testEngine.ColumnMapper.Obj2Table("Status")).Insert(&di2) + if err != nil { + t.Error(err) + } + + has, err := testEngine.Desc("(id)").Get(di) + if err != nil { + t.Error(err) + } + if !has { + err = errors.New("error with no data") + t.Error(err) + panic(err) + } + if di.Status != -1 { + err = errors.New("inserted error data") + t.Error(err) + panic(err) + } + if di2.Updated.Unix() != di.Updated.Unix() { + err = errors.New("updated should equal") + t.Error(err, di.Updated, di2.Updated) + panic(err) + } + if di2.Created.Unix() != di.Created.Unix() { + err = errors.New("created should equal") + t.Error(err, di.Created, di2.Created) + panic(err) + } +} + +type DefaultInsert2 struct { + Id int64 + Name string + Url string `xorm:"text"` + CheckTime time.Time `xorm:"not null default '2000-01-01 00:00:00' TIMESTAMP"` +} + +func TestInsertDefault2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + di := new(DefaultInsert2) + err := testEngine.Sync2(di) + if err != nil { + t.Error(err) + } + + var di2 = DefaultInsert2{Name: "test"} + _, err = testEngine.Omit(testEngine.ColumnMapper.Obj2Table("CheckTime")).Insert(&di2) + if err != nil { + t.Error(err) + } + + has, err := testEngine.Desc("(id)").Get(di) + if err != nil { + t.Error(err) + } + if !has { + err = errors.New("error with no data") + t.Error(err) + panic(err) + } + + has, err = testEngine.NoAutoCondition().Desc("(id)").Get(&di2) + if err != nil { + t.Error(err) + } + + if !has { + err = errors.New("error with no data") + t.Error(err) + panic(err) + } + + if *di != di2 { + err = fmt.Errorf("%v is not equal to %v", di, di2) + t.Error(err) + panic(err) + } + + /*if di2.Updated.Unix() != di.Updated.Unix() { + err = errors.New("updated should equal") + t.Error(err, di.Updated, di2.Updated) + panic(err) + } + if di2.Created.Unix() != di.Created.Unix() { + err = errors.New("created should equal") + t.Error(err, di.Created, di2.Created) + panic(err) + }*/ +} + +type CreatedInsert struct { + Id int64 + Created time.Time `xorm:"created"` +} + +type CreatedInsert2 struct { + Id int64 + Created int64 `xorm:"created"` +} + +type CreatedInsert3 struct { + Id int64 + Created int `xorm:"created bigint"` +} + +type CreatedInsert4 struct { + Id int64 + Created int `xorm:"created"` +} + +type CreatedInsert5 struct { + Id int64 + Created time.Time `xorm:"created bigint"` +} + +type CreatedInsert6 struct { + Id int64 + Created time.Time `xorm:"created bigint"` +} + +func TestInsertCreated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + di := new(CreatedInsert) + err := testEngine.Sync2(di) + if err != nil { + t.Fatal(err) + } + ci := &CreatedInsert{} + _, err = testEngine.Insert(ci) + if err != nil { + t.Fatal(err) + } + + has, err := testEngine.Desc("(id)").Get(di) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci.Created.Unix() != di.Created.Unix() { + t.Fatal("should equal:", ci, di) + } + fmt.Println("ci:", ci, "di:", di) + + di2 := new(CreatedInsert2) + err = testEngine.Sync2(di2) + if err != nil { + t.Fatal(err) + } + ci2 := &CreatedInsert2{} + _, err = testEngine.Insert(ci2) + if err != nil { + t.Fatal(err) + } + has, err = testEngine.Desc("(id)").Get(di2) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci2.Created != di2.Created { + t.Fatal("should equal:", ci2, di2) + } + fmt.Println("ci2:", ci2, "di2:", di2) + + di3 := new(CreatedInsert3) + err = testEngine.Sync2(di3) + if err != nil { + t.Fatal(err) + } + ci3 := &CreatedInsert3{} + _, err = testEngine.Insert(ci3) + if err != nil { + t.Fatal(err) + } + has, err = testEngine.Desc("(id)").Get(di3) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci3.Created != di3.Created { + t.Fatal("should equal:", ci3, di3) + } + fmt.Println("ci3:", ci3, "di3:", di3) + + di4 := new(CreatedInsert4) + err = testEngine.Sync2(di4) + if err != nil { + t.Fatal(err) + } + ci4 := &CreatedInsert4{} + _, err = testEngine.Insert(ci4) + if err != nil { + t.Fatal(err) + } + has, err = testEngine.Desc("(id)").Get(di4) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci4.Created != di4.Created { + t.Fatal("should equal:", ci4, di4) + } + fmt.Println("ci4:", ci4, "di4:", di4) + + di5 := new(CreatedInsert5) + err = testEngine.Sync2(di5) + if err != nil { + t.Fatal(err) + } + ci5 := &CreatedInsert5{} + _, err = testEngine.Insert(ci5) + if err != nil { + t.Fatal(err) + } + has, err = testEngine.Desc("(id)").Get(di5) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci5.Created.Unix() != di5.Created.Unix() { + t.Fatal("should equal:", ci5, di5) + } + fmt.Println("ci5:", ci5, "di5:", di5) + + di6 := new(CreatedInsert6) + err = testEngine.Sync2(di6) + if err != nil { + t.Fatal(err) + } + oldTime := time.Now().Add(-time.Hour) + ci6 := &CreatedInsert6{Created: oldTime} + _, err = testEngine.Insert(ci6) + if err != nil { + t.Fatal(err) + } + + has, err = testEngine.Desc("(id)").Get(di6) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci6.Created.Unix() != di6.Created.Unix() { + t.Fatal("should equal:", ci6, di6) + } + fmt.Println("ci6:", ci6, "di6:", di6) +} + +type JsonTime time.Time + +func (j JsonTime) format() string { + t := time.Time(j) + if t.IsZero() { + return "" + } + + return t.Format("2006-01-02") +} + +func (j JsonTime) MarshalText() ([]byte, error) { + return []byte(j.format()), nil +} + +func (j JsonTime) MarshalJSON() ([]byte, error) { + return []byte(`"` + j.format() + `"`), nil +} + +type MyJsonTime struct { + Id int64 `json:"id"` + Created JsonTime `xorm:"created" json:"created_at"` +} + +func TestCreatedJsonTime(t *testing.T) { + assert.NoError(t, prepareEngine()) + + di5 := new(MyJsonTime) + err := testEngine.Sync2(di5) + if err != nil { + t.Fatal(err) + } + ci5 := &MyJsonTime{} + _, err = testEngine.Insert(ci5) + if err != nil { + t.Fatal(err) + } + has, err := testEngine.Desc("(id)").Get(di5) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if time.Time(ci5.Created).Unix() != time.Time(di5.Created).Unix() { + t.Fatal("should equal:", time.Time(ci5.Created).Unix(), time.Time(di5.Created).Unix()) + } + fmt.Println("ci5:", ci5, "di5:", di5) + + var dis = make([]MyJsonTime, 0) + err = testEngine.Find(&dis) + if err != nil { + t.Fatal(err) + } +} + +func TestInsertMulti2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assertSync(t, new(Userinfo)) + + users := []Userinfo{ + {Username: "xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()}, + {Username: "xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()}, + {Username: "xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()}, + {Username: "xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()}, + } + cnt, err := testEngine.Insert(&users) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != int64(len(users)) { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } + + users2 := []*Userinfo{ + &Userinfo{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()}, + &Userinfo{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()}, + &Userinfo{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()}, + &Userinfo{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()}, + } + + cnt, err = testEngine.Insert(&users2) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != int64(len(users2)) { + err = errors.New(fmt.Sprintf("insert not returned %v", len(users2))) + t.Error(err) + panic(err) + } +} + +func TestInsertTwoTable(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assertSync(t, new(Userinfo), new(Userdetail)) + + userdetail := Userdetail{ /*Id: 1, */ Intro: "I'm a very beautiful women.", Profile: "sfsaf"} + userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail} + + cnt, err := testEngine.Insert(&userinfo, &userdetail) + if err != nil { + t.Error(err) + panic(err) + } + + if userinfo.Uid <= 0 { + err = errors.New("not return id error") + t.Error(err) + panic(err) + } + + if userdetail.Id <= 0 { + err = errors.New("not return id error") + t.Error(err) + panic(err) + } + + if cnt != 2 { + err = errors.New("insert not returned 2") + t.Error(err) + panic(err) + } +} diff --git a/session_iterate_test.go b/session_iterate_test.go new file mode 100644 index 0000000..2c58c3a --- /dev/null +++ b/session_iterate_test.go @@ -0,0 +1,38 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIterate(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserIterate struct { + Id int64 + IsMan bool + } + + assert.NoError(t, testEngine.Sync2(new(UserIterate))) + + cnt, err := testEngine.Insert(&UserIterate{ + IsMan: true, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + cnt = 0 + err = testEngine.Iterate(new(UserIterate), func(i int, bean interface{}) error { + user := bean.(*UserIterate) + assert.EqualValues(t, 1, user.Id) + assert.EqualValues(t, true, user.IsMan) + cnt++ + return nil + }) + assert.EqualValues(t, 1, cnt) +} diff --git a/session_pk_test.go b/session_pk_test.go index 44ffb30..b9c7032 100644 --- a/session_pk_test.go +++ b/session_pk_test.go @@ -1105,3 +1105,15 @@ func TestMyStringId(t *testing.T) { panic(err) } } + +func TestSingleAutoIncrColumn(t *testing.T) { + type Account struct { + Id int64 `xorm:"pk autoincr"` + } + + assert.NoError(t, prepareEngine()) + assertSync(t, new(Account)) + + _, err := testEngine.Insert(&Account{}) + assert.NoError(t, err) +} diff --git a/session_raw_test.go b/session_raw_test.go index 126f617..1f2145b 100644 --- a/session_raw_test.go +++ b/session_raw_test.go @@ -5,6 +5,7 @@ package xorm import ( + "strconv" "testing" "time" @@ -41,3 +42,28 @@ func TestQueryString(t *testing.T) { assert.Equal(t, "28", records[0]["age"]) assert.Equal(t, "1.5", records[0]["money"]) } + +func TestQuery(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserinfoQuery struct { + Uid int + Name string + } + + assert.NoError(t, testEngine.Sync(new(UserinfoQuery))) + + res, err := testEngine.Exec("INSERT INTO `userinfo_query` (uid, name) VALUES (?, ?)", 1, "user") + assert.NoError(t, err) + cnt, err := res.RowsAffected() + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + results, err := testEngine.Query("select * from userinfo_query") + assert.NoError(t, err) + assert.EqualValues(t, 1, len(results)) + id, err := strconv.Atoi(string(results[0]["uid"])) + assert.NoError(t, err) + assert.EqualValues(t, 1, id) + assert.Equal(t, "user", string(results[0]["name"])) +} diff --git a/session_schema_test.go b/session_schema_test.go new file mode 100644 index 0000000..8a7016c --- /dev/null +++ b/session_schema_test.go @@ -0,0 +1,218 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestStoreEngine(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assert.NoError(t, testEngine.DropTables("user_store_engine")) + + type UserinfoStoreEngine struct { + Id int64 + Name string + } + + assert.NoError(t, testEngine.StoreEngine("InnoDB").Table("user_store_engine").CreateTable(&UserinfoStoreEngine{})) +} + +func TestCreateTable(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assert.NoError(t, testEngine.DropTables("user_user")) + + type UserinfoCreateTable struct { + Id int64 + Name string + } + + assert.NoError(t, testEngine.Table("user_user").CreateTable(&UserinfoCreateTable{})) +} + +func TestCreateMultiTables(t *testing.T) { + assert.NoError(t, prepareEngine()) + + session := testEngine.NewSession() + defer session.Close() + + type UserinfoMultiTable struct { + Id int64 + Name string + } + + user := &UserinfoMultiTable{} + assert.NoError(t, session.Begin()) + + for i := 0; i < 10; i++ { + tableName := fmt.Sprintf("user_%v", i) + + assert.NoError(t, session.DropTable(tableName)) + + assert.NoError(t, session.Table(tableName).CreateTable(user)) + } + + assert.NoError(t, session.Commit()) +} + +type SyncTable1 struct { + Id int64 + Name string + Dev int `xorm:"index"` +} + +type SyncTable2 struct { + Id int64 + Name string `xorm:"unique"` + Number string `xorm:"index"` + Dev int + Age int +} + +func (SyncTable2) TableName() string { + return "sync_table1" +} + +func TestSyncTable(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assert.NoError(t, testEngine.Sync2(new(SyncTable1))) + + assert.NoError(t, testEngine.Sync2(new(SyncTable2))) +} + +func TestIsTableExist(t *testing.T) { + assert.NoError(t, prepareEngine()) + + exist, err := testEngine.IsTableExist(new(CustomTableName)) + assert.NoError(t, err) + assert.False(t, exist) + + assert.NoError(t, testEngine.CreateTables(new(CustomTableName))) + + exist, err = testEngine.IsTableExist(new(CustomTableName)) + assert.NoError(t, err) + assert.True(t, exist) +} + +func TestIsTableEmpty(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type NumericEmpty struct { + Numeric float64 `xorm:"numeric(26,2)"` + } + + type PictureEmpty struct { + Id int64 + Url string `xorm:"unique"` //image's url + Title string + Description string + Created time.Time `xorm:"created"` + ILike int + PageView int + From_url string + Pre_url string `xorm:"unique"` //pre view image's url + Uid int64 + } + + assert.NoError(t, testEngine.DropTables(&PictureEmpty{}, &NumericEmpty{})) + + assert.NoError(t, testEngine.Sync(new(PictureEmpty), new(NumericEmpty))) + + isEmpty, err := testEngine.IsTableEmpty(&PictureEmpty{}) + assert.NoError(t, err) + assert.True(t, isEmpty) + + tbName := testEngine.TableMapper.Obj2Table("PictureEmpty") + isEmpty, err = testEngine.IsTableEmpty(tbName) + assert.NoError(t, err) + assert.True(t, isEmpty) +} + +type CustomTableName struct { + Id int64 + Name string +} + +func (c *CustomTableName) TableName() string { + return "customtablename" +} + +func TestCustomTableName(t *testing.T) { + assert.NoError(t, prepareEngine()) + + c := new(CustomTableName) + assert.NoError(t, testEngine.DropTables(c)) + + assert.NoError(t, testEngine.CreateTables(c)) +} + +func TestDump(t *testing.T) { + assert.NoError(t, prepareEngine()) + + fp := testEngine.Dialect().URI().DbName + ".sql" + os.Remove(fp) + assert.NoError(t, testEngine.DumpAllToFile(fp)) +} + +type IndexOrUnique struct { + Id int64 + Index int `xorm:"index"` + Unique int `xorm:"unique"` + Group1 int `xorm:"index(ttt)"` + Group2 int `xorm:"index(ttt)"` + UniGroup1 int `xorm:"unique(lll)"` + UniGroup2 int `xorm:"unique(lll)"` +} + +func TestIndexAndUnique(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assert.NoError(t, testEngine.CreateTables(&IndexOrUnique{})) + + assert.NoError(t, testEngine.DropTables(&IndexOrUnique{})) + + assert.NoError(t, testEngine.CreateTables(&IndexOrUnique{})) + + assert.NoError(t, testEngine.CreateIndexes(&IndexOrUnique{})) + + assert.NoError(t, testEngine.CreateUniques(&IndexOrUnique{})) + + assert.NoError(t, testEngine.DropIndexes(&IndexOrUnique{})) +} + +func TestMetaInfo(t *testing.T) { + assert.NoError(t, prepareEngine()) + assert.NoError(t, testEngine.Sync2(new(CustomTableName), new(IndexOrUnique))) + + tables, err := testEngine.DBMetas() + assert.NoError(t, err) + assert.EqualValues(t, 2, len(tables)) + assert.EqualValues(t, "customtablename", tables[0].Name) + assert.EqualValues(t, "index_or_unique", tables[1].Name) +} + +func TestCharst(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables("user_charset") + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.Charset("utf8").Table("user_charset").CreateTable(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } +} diff --git a/session_sum_test.go b/session_sum_test.go index 31a65f9..0519065 100644 --- a/session_sum_test.go +++ b/session_sum_test.go @@ -9,6 +9,7 @@ import ( "strconv" "testing" + "github.com/go-xorm/builder" "github.com/stretchr/testify/assert" ) @@ -99,3 +100,31 @@ func TestSumCustomColumn(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 3, int(sumInt)) } + +func TestCount(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserinfoCount struct { + Departname string + } + assert.NoError(t, testEngine.Sync2(new(UserinfoCount))) + + colName := testEngine.ColumnMapper.Obj2Table("Departname") + var cond builder.Cond = builder.Eq{ + "`" + colName + "`": "dev", + } + + total, err := testEngine.Where(cond).Count(new(UserinfoCount)) + assert.NoError(t, err) + assert.EqualValues(t, 0, total) + + cnt, err := testEngine.Insert(&UserinfoCount{ + Departname: "dev", + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + total, err = testEngine.Where(cond).Count(new(UserinfoCount)) + assert.NoError(t, err) + assert.EqualValues(t, 1, total) +} diff --git a/session_tx_test.go b/session_tx_test.go new file mode 100644 index 0000000..d56813c --- /dev/null +++ b/session_tx_test.go @@ -0,0 +1,192 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/xormplus/core" +) + +func TestTransaction(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + counter := func() { + total, err := testEngine.Count(&Userinfo{}) + if err != nil { + t.Error(err) + } + fmt.Printf("----now total %v records\n", total) + } + + counter() + //defer counter() + + session := testEngine.NewSession() + defer session.Close() + + err := session.Begin() + if err != nil { + t.Error(err) + panic(err) + return + } + + user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} + _, err = session.Insert(&user1) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + return + } + + user2 := Userinfo{Username: "yyy"} + _, err = session.Where("(id) = ?", 0).Update(&user2) + if err != nil { + session.Rollback() + fmt.Println(err) + //t.Error(err) + return + } + + _, err = session.Delete(&user2) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + return + } + + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + return + } + // panic(err) !nashtsai! should remove this +} + +func TestCombineTransaction(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + counter := func() { + total, err := testEngine.Count(&Userinfo{}) + if err != nil { + t.Error(err) + } + fmt.Printf("----now total %v records\n", total) + } + + counter() + //defer counter() + session := testEngine.NewSession() + defer session.Close() + + err := session.Begin() + if err != nil { + t.Error(err) + panic(err) + } + + user1 := Userinfo{Username: "xiaoxiao2", Departname: "dev", Alias: "lunny", Created: time.Now()} + _, err = session.Insert(&user1) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + } + user2 := Userinfo{Username: "zzz"} + _, err = session.Where("id = ?", 0).Update(&user2) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + } + + _, err = session.Exec("delete from userinfo where username = ?", user2.Username) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + } + + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestCombineTransactionSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + + oldMapper := testEngine.ColumnMapper + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(core.SameMapper{}) + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(oldMapper) + }() + + assertSync(t, new(Userinfo)) + + counter := func() { + total, err := testEngine.Count(&Userinfo{}) + if err != nil { + t.Error(err) + } + fmt.Printf("----now total %v records\n", total) + } + + counter() + defer counter() + session := testEngine.NewSession() + defer session.Close() + + err := session.Begin() + if err != nil { + t.Error(err) + panic(err) + return + } + + user1 := Userinfo{Username: "xiaoxiao2", Departname: "dev", Alias: "lunny", Created: time.Now()} + _, err = session.Insert(&user1) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + return + } + + user2 := Userinfo{Username: "zzz"} + _, err = session.Where("(id) = ?", 0).Update(&user2) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + return + } + + _, err = session.Exec("delete from `Userinfo` where `Username` = ?", user2.Username) + if err != nil { + session.Rollback() + t.Error(err) + panic(err) + return + } + + err = session.Commit() + if err != nil { + t.Error(err) + panic(err) + } +} diff --git a/session_update_test.go b/session_update_test.go index 22d3c5a..74fb6ab 100644 --- a/session_update_test.go +++ b/session_update_test.go @@ -5,10 +5,14 @@ package xorm import ( + "errors" + "fmt" + "sync" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/xormplus/core" ) func TestUpdateMap(t *testing.T) { @@ -74,26 +78,1033 @@ func TestUpdateLimit(t *testing.T) { assert.EqualValues(t, 30, uts[1].Age) } -func TestUpdate(t *testing.T) { - assert.NoError(t, prepareEngine()) +type ForUpdate struct { + Id int64 `xorm:"pk"` + Name string +} + +func setupForUpdate(engine *Engine) error { + v := new(ForUpdate) + err := testEngine.DropTables(v) + if err != nil { + return err + } + err = testEngine.CreateTables(v) + if err != nil { + return err + } + + list := []ForUpdate{ + {1, "data1"}, + {2, "data2"}, + {3, "data3"}, + } + + for _, f := range list { + _, err = testEngine.Insert(f) + if err != nil { + return err + } + } + return nil +} + +func TestForUpdate(t *testing.T) { + if testEngine.DriverName() != "mysql" && testEngine.DriverName() != "mymysql" { + return + } + + err := setupForUpdate(testEngine) + if err != nil { + t.Error(err) + return + } + + session1 := testEngine.NewSession() + session2 := testEngine.NewSession() + session3 := testEngine.NewSession() + defer session1.Close() + defer session2.Close() + defer session3.Close() + + // start transaction + err = session1.Begin() + if err != nil { + t.Error(err) + return + } + + // use lock + fList := make([]ForUpdate, 0) + session1.ForUpdate() + session1.Where("(id) = ?", 1) + err = session1.Find(&fList) + switch { + case err != nil: + t.Error(err) + return + case len(fList) != 1: + t.Errorf("find not returned single row") + return + case fList[0].Name != "data1": + t.Errorf("for_update.name must be `data1`") + return + } + + // wait for lock + wg := &sync.WaitGroup{} + + // lock is used + wg.Add(1) + go func() { + f2 := new(ForUpdate) + session2.Where("(id) = ?", 1).ForUpdate() + has, err := session2.Get(f2) // wait release lock + switch { + case err != nil: + t.Error(err) + case !has: + t.Errorf("cannot find target row. for_update.id = 1") + case f2.Name != "updated by session1": + t.Errorf("read lock failed") + } + wg.Done() + }() + + // lock is NOT used + wg.Add(1) + go func() { + f3 := new(ForUpdate) + session3.Where("(id) = ?", 1) + has, err := session3.Get(f3) // wait release lock + switch { + case err != nil: + t.Error(err) + case !has: + t.Errorf("cannot find target row. for_update.id = 1") + case f3.Name != "data1": + t.Errorf("read lock failed") + } + wg.Done() + }() + + // wait for go rountines + time.Sleep(50 * time.Millisecond) + + f := new(ForUpdate) + f.Name = "updated by session1" + session1.Where("(id) = ?", 1) + session1.Update(f) - type UpdateTable2 struct { - Id int64 `xorm:"autoincr pk"` - Msg string `xorm:"varchar(255)"` - Created time.Time `xorm:"datetime updated"` + // release lock + err = session1.Commit() + if err != nil { + t.Error(err) + return } - assert.NoError(t, testEngine.Sync2(new(UpdateTable2))) + wg.Wait() +} + +func TestWithIn(t *testing.T) { + type temp3 struct { + Id int64 `xorm:"Id pk autoincr"` + Name string `xorm:"Name"` + Test bool `xorm:"Test"` + } + + assert.NoError(t, prepareEngine()) + assert.NoError(t, testEngine.Sync(new(temp3))) - data := UpdateTable2{Msg: "test1"} + testEngine.Insert(&[]temp3{ + { + Name: "user1", + }, + { + Name: "user1", + }, + { + Name: "user1", + }, + }) - cnt, err := testEngine.Insert(&data) + cnt, err := testEngine.In("Id", 1, 2, 3, 4).Update(&temp3{Name: "aa"}, &temp3{Name: "user1"}) assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) + assert.EqualValues(t, 3, cnt) +} - cnt, err = testEngine.Where("id = ?", data.Id).Update(&UpdateTable2{ - Msg: "test2", +type Condi map[string]interface{} + +type UpdateAllCols struct { + Id int64 + Bool bool + String string + Ptr *string +} + +type UpdateMustCols struct { + Id int64 + Bool bool + String string +} + +type UpdateIncr struct { + Id int64 + Cnt int +} + +type Article struct { + Id int32 `xorm:"pk INT autoincr"` + Name string `xorm:"VARCHAR(45)"` + Img string `xorm:"VARCHAR(100)"` + Aside string `xorm:"VARCHAR(200)"` + Desc string `xorm:"VARCHAR(200)"` + Content string `xorm:"TEXT"` + Status int8 `xorm:"TINYINT(4)"` +} + +func TestUpdateMap2(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(UpdateMustCols)) + + _, err := testEngine.Table("update_must_cols").Where("id =?", 1).Update(map[string]interface{}{ + "bool": true, + }) + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestUpdate1(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + _, err := testEngine.Insert(&Userinfo{ + Username: "user1", + }) + + var ori Userinfo + has, err := testEngine.Get(&ori) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + t.Error(errors.New("not exist")) + panic(errors.New("not exist")) + } + + // update by id + user := Userinfo{Username: "xxx", Height: 1.2} + cnt, err := testEngine.Id(ori.Uid).Update(&user) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + condi := Condi{"username": "zzz", "departname": ""} + cnt, err = testEngine.Table(&user).Id(ori.Uid).Update(&condi) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + cnt, err = testEngine.Update(&Userinfo{Username: "yyy"}, &user) + if err != nil { + t.Error(err) + panic(err) + } + total, err := testEngine.Count(&user) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != total { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } + + // nullable update + { + user := &Userinfo{Username: "not null data", Height: 180.5} + _, err := testEngine.Insert(user) + if err != nil { + t.Error(err) + panic(err) + } + userID := user.Uid + + has, err := testEngine.Id(userID). + And("username = ?", user.Username). + And("height = ?", user.Height). + And("departname = ?", ""). + And("detail_id = ?", 0). + And("is_man = ?", 0). + Get(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("cannot insert properly") + t.Error(err) + panic(err) + } + + updatedUser := &Userinfo{Username: "null data"} + cnt, err = testEngine.Id(userID). + Nullable("height", "departname", "is_man", "created"). + Update(updatedUser) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + } + + has, err = testEngine.Id(userID). + And("username = ?", updatedUser.Username). + And("height IS NULL"). + And("departname IS NULL"). + And("is_man IS NULL"). + And("created IS NULL"). + And("detail_id = ?", 0). + Get(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("cannot update with null properly") + t.Error(err) + panic(err) + } + + cnt, err = testEngine.Id(userID).Delete(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("delete not returned 1") + t.Error(err) + panic(err) + } + } + + err = testEngine.StoreEngine("Innodb").Sync2(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + + defer func() { + err = testEngine.DropTables(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + }() + + a := &Article{0, "1", "2", "3", "4", "5", 2} + cnt, err = testEngine.Insert(a) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) + t.Error(err) + panic(err) + } + + if a.Id == 0 { + err = errors.New("insert returned id is 0") + t.Error(err) + panic(err) + } + + cnt, err = testEngine.Id(a.Id).Update(&Article{Name: "6"}) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) + t.Error(err) + panic(err) + return + } + + var s = "test" + + col1 := &UpdateAllCols{Ptr: &s} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateAllCols{col1.Id, true, "", nil} + _, err = testEngine.Id(col2.Id).AllCols().Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateAllCols{} + has, err = testEngine.Id(col2.Id).Get(col3) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + err = errors.New(fmt.Sprintf("cannot get id %d", col2.Id)) + t.Error(err) + panic(err) + return + } + + if *col2 != *col3 { + err = errors.New(fmt.Sprintf("col2 should eq col3")) + t.Error(err) + panic(err) + return + } + + { + + col1 := &UpdateMustCols{} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateMustCols{col1.Id, true, ""} + boolStr := testEngine.ColumnMapper.Obj2Table("Bool") + stringStr := testEngine.ColumnMapper.Obj2Table("String") + _, err = testEngine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateMustCols{} + has, err := testEngine.Id(col2.Id).Get(col3) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + err = errors.New(fmt.Sprintf("cannot get id %d", col2.Id)) + t.Error(err) + panic(err) + return + } + + if *col2 != *col3 { + err = errors.New(fmt.Sprintf("col2 should eq col3")) + t.Error(err) + panic(err) + return + } + } + + { + + col1 := &UpdateIncr{} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + cnt, err := testEngine.Id(col1.Id).Incr(testEngine.ColumnMapper.Obj2Table("Cnt")).Update(col1) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update incr failed") + t.Error(err) + panic(err) + } + + newCol := new(UpdateIncr) + has, err := testEngine.Id(col1.Id).Get(newCol) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("has incr failed") + t.Error(err) + panic(err) + } + if 1 != newCol.Cnt { + err = fmt.Errorf("incr failed %v %v %v", newCol.Cnt, newCol, col1) + t.Error(err) + panic(err) + } + } +} + +type UpdatedUpdate struct { + Id int64 + Updated time.Time `xorm:"updated"` +} + +type UpdatedUpdate2 struct { + Id int64 + Updated int64 `xorm:"updated"` +} + +type UpdatedUpdate3 struct { + Id int64 + Updated int `xorm:"updated bigint"` +} + +type UpdatedUpdate4 struct { + Id int64 + Updated int `xorm:"updated"` +} + +type UpdatedUpdate5 struct { + Id int64 + Updated time.Time `xorm:"updated bigint"` +} + +func TestUpdateUpdated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + di := new(UpdatedUpdate) + err := testEngine.Sync2(di) + if err != nil { + t.Fatal(err) + } + + _, err = testEngine.Insert(&UpdatedUpdate{}) + if err != nil { + t.Fatal(err) + } + + ci := &UpdatedUpdate{} + _, err = testEngine.Id(1).Update(ci) + if err != nil { + t.Fatal(err) + } + + has, err := testEngine.Id(1).Get(di) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci.Updated.Unix() != di.Updated.Unix() { + t.Fatal("should equal:", ci, di) + } + fmt.Println("ci:", ci, "di:", di) + + di2 := new(UpdatedUpdate2) + err = testEngine.Sync2(di2) + if err != nil { + t.Fatal(err) + } + + _, err = testEngine.Insert(&UpdatedUpdate2{}) + if err != nil { + t.Fatal(err) + } + ci2 := &UpdatedUpdate2{} + _, err = testEngine.Id(1).Update(ci2) + if err != nil { + t.Fatal(err) + } + has, err = testEngine.Id(1).Get(di2) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci2.Updated != di2.Updated { + t.Fatal("should equal:", ci2, di2) + } + fmt.Println("ci2:", ci2, "di2:", di2) + + di3 := new(UpdatedUpdate3) + err = testEngine.Sync2(di3) + if err != nil { + t.Fatal(err) + } + + _, err = testEngine.Insert(&UpdatedUpdate3{}) + if err != nil { + t.Fatal(err) + } + ci3 := &UpdatedUpdate3{} + _, err = testEngine.Id(1).Update(ci3) + if err != nil { + t.Fatal(err) + } + + has, err = testEngine.Id(1).Get(di3) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci3.Updated != di3.Updated { + t.Fatal("should equal:", ci3, di3) + } + fmt.Println("ci3:", ci3, "di3:", di3) + + di4 := new(UpdatedUpdate4) + err = testEngine.Sync2(di4) + if err != nil { + t.Fatal(err) + } + + _, err = testEngine.Insert(&UpdatedUpdate4{}) + if err != nil { + t.Fatal(err) + } + + ci4 := &UpdatedUpdate4{} + _, err = testEngine.Id(1).Update(ci4) + if err != nil { + t.Fatal(err) + } + + has, err = testEngine.Id(1).Get(di4) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci4.Updated != di4.Updated { + t.Fatal("should equal:", ci4, di4) + } + fmt.Println("ci4:", ci4, "di4:", di4) + + di5 := new(UpdatedUpdate5) + err = testEngine.Sync2(di5) + if err != nil { + t.Fatal(err) + } + + _, err = testEngine.Insert(&UpdatedUpdate5{}) + if err != nil { + t.Fatal(err) + } + ci5 := &UpdatedUpdate5{} + _, err = testEngine.Id(1).Update(ci5) + if err != nil { + t.Fatal(err) + } + + has, err = testEngine.Id(1).Get(di5) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal(ErrNotExist) + } + if ci5.Updated.Unix() != di5.Updated.Unix() { + t.Fatal("should equal:", ci5, di5) + } + fmt.Println("ci5:", ci5, "di5:", di5) +} + +func TestUpdateSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + + oldMapper := testEngine.ColumnMapper + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.unMapType(rValue(new(Condi)).Type()) + testEngine.unMapType(rValue(new(Article)).Type()) + testEngine.unMapType(rValue(new(UpdateAllCols)).Type()) + testEngine.unMapType(rValue(new(UpdateMustCols)).Type()) + testEngine.unMapType(rValue(new(UpdateIncr)).Type()) + testEngine.SetMapper(core.SameMapper{}) + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.unMapType(rValue(new(Condi)).Type()) + testEngine.unMapType(rValue(new(Article)).Type()) + testEngine.unMapType(rValue(new(UpdateAllCols)).Type()) + testEngine.unMapType(rValue(new(UpdateMustCols)).Type()) + testEngine.unMapType(rValue(new(UpdateIncr)).Type()) + testEngine.SetMapper(oldMapper) + }() + + assertSync(t, new(Userinfo)) + + _, err := testEngine.Insert(&Userinfo{ + Username: "user1", }) assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) + + var ori Userinfo + has, err := testEngine.Get(&ori) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + t.Error(errors.New("not exist")) + panic(errors.New("not exist")) + } + // update by id + user := Userinfo{Username: "xxx", Height: 1.2} + cnt, err := testEngine.Id(ori.Uid).Update(&user) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + condi := Condi{"Username": "zzz", "Departname": ""} + cnt, err = testEngine.Table(&user).Id(ori.Uid).Update(&condi) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + cnt, err = testEngine.Update(&Userinfo{Username: "yyy"}, &user) + if err != nil { + t.Error(err) + panic(err) + } + + total, err := testEngine.Count(&user) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != total { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } + + err = testEngine.Sync(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + + defer func() { + err = testEngine.DropTables(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + }() + + a := &Article{0, "1", "2", "3", "4", "5", 2} + cnt, err = testEngine.Insert(a) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) + t.Error(err) + panic(err) + } + + if a.Id == 0 { + err = errors.New("insert returned id is 0") + t.Error(err) + panic(err) + } + + cnt, err = testEngine.Id(a.Id).Update(&Article{Name: "6"}) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) + t.Error(err) + panic(err) + return + } + + col1 := &UpdateAllCols{} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateAllCols{col1.Id, true, "", nil} + _, err = testEngine.Id(col2.Id).AllCols().Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateAllCols{} + has, err = testEngine.Id(col2.Id).Get(col3) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + err = errors.New(fmt.Sprintf("cannot get id %d", col2.Id)) + t.Error(err) + panic(err) + return + } + + if *col2 != *col3 { + err = errors.New(fmt.Sprintf("col2 should eq col3")) + t.Error(err) + panic(err) + return + } + + { + col1 := &UpdateMustCols{} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateMustCols{col1.Id, true, ""} + boolStr := testEngine.ColumnMapper.Obj2Table("Bool") + stringStr := testEngine.ColumnMapper.Obj2Table("String") + _, err = testEngine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateMustCols{} + has, err := testEngine.Id(col2.Id).Get(col3) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + err = errors.New(fmt.Sprintf("cannot get id %d", col2.Id)) + t.Error(err) + panic(err) + return + } + + if *col2 != *col3 { + err = errors.New(fmt.Sprintf("col2 should eq col3")) + t.Error(err) + panic(err) + return + } + } + + { + + col1 := &UpdateIncr{} + err = testEngine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + cnt, err := testEngine.Id(col1.Id).Incr("`Cnt`").Update(col1) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update incr failed") + t.Error(err) + panic(err) + } + + newCol := new(UpdateIncr) + has, err := testEngine.Id(col1.Id).Get(newCol) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + err = errors.New("has incr failed") + t.Error(err) + panic(err) + } + if 1 != newCol.Cnt { + err = errors.New("incr failed") + t.Error(err) + panic(err) + } + } +} + +func TestUseBool(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + cnt1, err := testEngine.Count(&Userinfo{}) + if err != nil { + t.Error(err) + panic(err) + } + + users := make([]Userinfo, 0) + err = testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + var fNumber int64 + for _, u := range users { + if u.IsMan == false { + fNumber += 1 + } + } + + cnt2, err := testEngine.UseBool().Update(&Userinfo{IsMan: true}) + if err != nil { + t.Error(err) + panic(err) + } + if fNumber != cnt2 { + fmt.Println("cnt1", cnt1, "fNumber", fNumber, "cnt2", cnt2) + /*err = errors.New("Updated number is not corrected.") + t.Error(err) + panic(err)*/ + } + + _, err = testEngine.Update(&Userinfo{IsMan: true}) + if err == nil { + err = errors.New("error condition") + t.Error(err) + panic(err) + } +} + +func TestBool(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + _, err := testEngine.UseBool().Update(&Userinfo{IsMan: true}) + if err != nil { + t.Error(err) + panic(err) + } + users := make([]Userinfo, 0) + err = testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + if !user.IsMan { + err = errors.New("update bool or find bool error") + t.Error(err) + panic(err) + } + } + + _, err = testEngine.UseBool().Update(&Userinfo{IsMan: false}) + if err != nil { + t.Error(err) + panic(err) + } + users = make([]Userinfo, 0) + err = testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + if user.IsMan { + err = errors.New("update bool or find bool error") + t.Error(err) + panic(err) + } + } } diff --git a/statement_test.go b/statement_test.go index 6788a89..6f5d29b 100644 --- a/statement_test.go +++ b/statement_test.go @@ -26,7 +26,7 @@ var colStrTests = []struct { } func TestColumnsStringGeneration(t *testing.T) { - if *db == "postgres" { + if dbType == "postgres" || dbType == "mssql" { return } diff --git a/tag_cache_test.go b/tag_cache_test.go new file mode 100644 index 0000000..14a65fb --- /dev/null +++ b/tag_cache_test.go @@ -0,0 +1,39 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCacheTag(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type CacheDomain struct { + Id int64 `xorm:"pk cache"` + Name string + } + + assert.NoError(t, testEngine.CreateTables(&CacheDomain{})) + + table := testEngine.TableInfo(&CacheDomain{}) + assert.True(t, table.Cacher != nil) +} + +func TestNoCacheTag(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type NoCacheDomain struct { + Id int64 `xorm:"pk nocache"` + Name string + } + + assert.NoError(t, testEngine.CreateTables(&NoCacheDomain{})) + + table := testEngine.TableInfo(&NoCacheDomain{}) + assert.True(t, table.Cacher == nil) +} diff --git a/tag_extends_test.go b/tag_extends_test.go new file mode 100644 index 0000000..0382e36 --- /dev/null +++ b/tag_extends_test.go @@ -0,0 +1,538 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/xormplus/core" +) + +type tempUser struct { + Id int64 + Username string +} + +type tempUser2 struct { + TempUser tempUser `xorm:"extends"` + Departname string +} + +type tempUser3 struct { + Temp *tempUser `xorm:"extends"` + Departname string +} + +type tempUser4 struct { + TempUser2 tempUser2 `xorm:"extends"` +} + +type Userinfo struct { + Uid int64 `xorm:"id pk not null autoincr"` + Username string `xorm:"unique"` + Departname string + Alias string `xorm:"-"` + Created time.Time + Detail Userdetail `xorm:"detail_id int(11)"` + Height float64 + Avatar []byte + IsMan bool +} + +type Userdetail struct { + Id int64 + Intro string `xorm:"text"` + Profile string `xorm:"varchar(2000)"` +} + +type UserAndDetail struct { + Userinfo `xorm:"extends"` + Userdetail `xorm:"extends"` +} + +func TestExtends(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&tempUser2{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser2{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu := &tempUser2{tempUser{0, "extends"}, "dev depart"} + _, err = testEngine.Insert(tu) + if err != nil { + t.Error(err) + panic(err) + } + + tu2 := &tempUser2{} + _, err = testEngine.Get(tu2) + if err != nil { + t.Error(err) + panic(err) + } + + tu3 := &tempUser2{tempUser{0, "extends update"}, ""} + _, err = testEngine.Id(tu2.TempUser.Id).Update(tu3) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.DropTables(&tempUser4{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser4{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu8 := &tempUser4{tempUser2{tempUser{0, "extends"}, "dev depart"}} + _, err = testEngine.Insert(tu8) + if err != nil { + t.Error(err) + panic(err) + } + + tu9 := &tempUser4{} + _, err = testEngine.Get(tu9) + if err != nil { + t.Error(err) + panic(err) + } + if tu9.TempUser2.TempUser.Username != tu8.TempUser2.TempUser.Username || tu9.TempUser2.Departname != tu8.TempUser2.Departname { + err = errors.New(fmt.Sprintln("not equal for", tu8, tu9)) + t.Error(err) + panic(err) + } + + tu10 := &tempUser4{tempUser2{tempUser{0, "extends update"}, ""}} + _, err = testEngine.Id(tu9.TempUser2.TempUser.Id).Update(tu10) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.DropTables(&tempUser3{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser3{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu4 := &tempUser3{&tempUser{0, "extends"}, "dev depart"} + _, err = testEngine.Insert(tu4) + if err != nil { + t.Error(err) + panic(err) + } + + tu5 := &tempUser3{} + _, err = testEngine.Get(tu5) + if err != nil { + t.Error(err) + panic(err) + } + if tu5.Temp == nil { + err = errors.New("error get data extends") + t.Error(err) + panic(err) + } + if tu5.Temp.Id != 1 || tu5.Temp.Username != "extends" || + tu5.Departname != "dev depart" { + err = errors.New("error get data extends") + t.Error(err) + panic(err) + } + + tu6 := &tempUser3{&tempUser{0, "extends update"}, ""} + _, err = testEngine.Id(tu5.Temp.Id).Update(tu6) + if err != nil { + t.Error(err) + panic(err) + } + + users := make([]tempUser3, 0) + err = testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + if len(users) != 1 { + err = errors.New("error get data not 1") + t.Error(err) + panic(err) + } + + assertSync(t, new(Userinfo), new(Userdetail)) + + detail := Userdetail{ + Intro: "I'm in China", + } + _, err = testEngine.Insert(&detail) + assert.NoError(t, err) + + _, err = testEngine.Insert(&Userinfo{ + Username: "lunny", + Detail: detail, + }) + assert.NoError(t, err) + + var info UserAndDetail + qt := testEngine.Quote + ui := testEngine.TableMapper.Obj2Table("Userinfo") + ud := testEngine.TableMapper.Obj2Table("Userdetail") + uiid := testEngine.TableMapper.Obj2Table("Id") + udid := "detail_id" + sql := fmt.Sprintf("select * from %s, %s where %s.%s = %s.%s", + qt(ui), qt(ud), qt(ui), qt(udid), qt(ud), qt(uiid)) + b, err := testEngine.Sql(sql).NoCascade().Get(&info) + if err != nil { + t.Error(err) + panic(err) + } + if !b { + err = errors.New("should has lest one record") + t.Error(err) + panic(err) + } + fmt.Println(info) + if info.Userinfo.Uid == 0 || info.Userdetail.Id == 0 { + err = errors.New("all of the id should has value") + t.Error(err) + panic(err) + } + + fmt.Println("----join--info2") + var info2 UserAndDetail + b, err = testEngine.Table(&Userinfo{}). + Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)). + NoCascade().Get(&info2) + if err != nil { + t.Error(err) + panic(err) + } + if !b { + err = errors.New("should has lest one record") + t.Error(err) + panic(err) + } + if info2.Userinfo.Uid == 0 || info2.Userdetail.Id == 0 { + err = errors.New("all of the id should has value") + t.Error(err) + panic(err) + } + fmt.Println(info2) + + fmt.Println("----join--infos2") + var infos2 = make([]UserAndDetail, 0) + err = testEngine.Table(&Userinfo{}). + Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)). + NoCascade(). + Find(&infos2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(infos2) +} + +type MessageBase struct { + Id int64 `xorm:"int(11) pk autoincr"` + TypeId int64 `xorm:"int(11) notnull"` +} + +type Message struct { + MessageBase `xorm:"extends"` + Title string `xorm:"varchar(100) notnull"` + Content string `xorm:"text notnull"` + Uid int64 `xorm:"int(11) notnull"` + ToUid int64 `xorm:"int(11) notnull"` + CreateTime time.Time `xorm:"datetime notnull created"` +} + +type MessageUser struct { + Id int64 + Name string +} + +type MessageType struct { + Id int64 + Name string +} + +type MessageExtend3 struct { + Message `xorm:"extends"` + Sender MessageUser `xorm:"extends"` + Receiver MessageUser `xorm:"extends"` + Type MessageType `xorm:"extends"` +} + +type MessageExtend4 struct { + Message `xorm:"extends"` + MessageUser `xorm:"extends"` + MessageType `xorm:"extends"` +} + +func TestExtends2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var receiver = MessageUser{Name: "receiver"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &receiver, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + ToUid: receiver.Id, + } + if testEngine.dialect.DBType() == core.MSSQL { + _, err = testEngine.Exec("SET IDENTITY_INSERT message ON") + assert.NoError(t, err) + } + + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]Message, 0) + err = testEngine.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("ToUid")+"`"). + Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0], msg)) + t.Error(err) + panic(err) + } +} + +func TestExtends3(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var receiver = MessageUser{Name: "receiver"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &receiver, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + ToUid: receiver.Id, + } + if testEngine.dialect.DBType() == core.MSSQL { + _, err = testEngine.Exec("SET IDENTITY_INSERT message ON") + assert.NoError(t, err) + } + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]MessageExtend3, 0) + err = testEngine.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("ToUid")+"`"). + Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Message.Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg)) + t.Error(err) + panic(err) + } + + if list[0].Sender.Id != sender.Id || list[0].Sender.Name != sender.Name { + err = errors.New(fmt.Sprintln("should sender equal", list[0].Sender, sender)) + t.Error(err) + panic(err) + } + + if list[0].Receiver.Id != receiver.Id || list[0].Receiver.Name != receiver.Name { + err = errors.New(fmt.Sprintln("should receiver equal", list[0].Receiver, receiver)) + t.Error(err) + panic(err) + } + + if list[0].Type.Id != msgtype.Id || list[0].Type.Name != msgtype.Name { + err = errors.New(fmt.Sprintln("should msgtype equal", list[0].Type, msgtype)) + t.Error(err) + panic(err) + } +} + +func TestExtends4(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + } + if testEngine.dialect.DBType() == core.MSSQL { + _, err = testEngine.Exec("SET IDENTITY_INSERT message ON") + assert.NoError(t, err) + } + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]MessageExtend4, 0) + err = testEngine.Table(msgTableName).Join("LEFT", userTableName, "`"+userTableName+"`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", typeTableName, "`"+typeTableName+"`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Message.Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg)) + t.Error(err) + panic(err) + } + + if list[0].MessageUser.Id != sender.Id || list[0].MessageUser.Name != sender.Name { + err = errors.New(fmt.Sprintln("should sender equal", list[0].MessageUser, sender)) + t.Error(err) + panic(err) + } + + if list[0].MessageType.Id != msgtype.Id || list[0].MessageType.Name != msgtype.Name { + err = errors.New(fmt.Sprintln("should msgtype equal", list[0].MessageType, msgtype)) + t.Error(err) + panic(err) + } +} diff --git a/tag_id_test.go b/tag_id_test.go new file mode 100644 index 0000000..54e79a8 --- /dev/null +++ b/tag_id_test.go @@ -0,0 +1,85 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/xormplus/core" +) + +type IDGonicMapper struct { + ID int64 +} + +func TestGonicMapperID(t *testing.T) { + assert.NoError(t, prepareEngine()) + + oldMapper := testEngine.ColumnMapper + testEngine.unMapType(rValue(new(IDGonicMapper)).Type()) + testEngine.SetMapper(core.LintGonicMapper) + defer func() { + testEngine.unMapType(rValue(new(IDGonicMapper)).Type()) + testEngine.SetMapper(oldMapper) + }() + + err := testEngine.CreateTables(new(IDGonicMapper)) + if err != nil { + t.Fatal(err) + } + + tables, err := testEngine.DBMetas() + if err != nil { + t.Fatal(err) + } + + for _, tb := range tables { + if tb.Name == "id_gonic_mapper" { + if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "id" { + t.Fatal(tb) + } + return + } + } + + t.Fatal("not table id_gonic_mapper") +} + +type IDSameMapper struct { + ID int64 +} + +func TestSameMapperID(t *testing.T) { + assert.NoError(t, prepareEngine()) + + oldMapper := testEngine.ColumnMapper + testEngine.unMapType(rValue(new(IDSameMapper)).Type()) + testEngine.SetMapper(core.SameMapper{}) + defer func() { + testEngine.unMapType(rValue(new(IDSameMapper)).Type()) + testEngine.SetMapper(oldMapper) + }() + + err := testEngine.CreateTables(new(IDSameMapper)) + if err != nil { + t.Fatal(err) + } + + tables, err := testEngine.DBMetas() + if err != nil { + t.Fatal(err) + } + + for _, tb := range tables { + if tb.Name == "IDSameMapper" { + if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "ID" { + t.Fatal(tb) + } + return + } + } + t.Fatal("not table IDSameMapper") +} diff --git a/tag_test.go b/tag_test.go new file mode 100644 index 0000000..4201b1c --- /dev/null +++ b/tag_test.go @@ -0,0 +1,189 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +type UserCU struct { + Id int64 + Name string + Created time.Time `xorm:"created"` + Updated time.Time `xorm:"updated"` +} + +func TestCreatedAndUpdated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + u := new(UserCU) + err := testEngine.DropTables(u) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(u) + if err != nil { + t.Error(err) + panic(err) + } + + u.Name = "sss" + cnt, err := testEngine.Insert(u) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } + + u.Name = "xxx" + cnt, err = testEngine.Id(u.Id).Update(u) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + u.Id = 0 + u.Created = time.Now().Add(-time.Hour * 24 * 365) + u.Updated = u.Created + fmt.Println(u) + cnt, err = testEngine.NoAutoTime().Insert(u) + if err != nil { + t.Error(err) + panic(err) + } + if cnt != 1 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } +} + +type StrangeName struct { + Id_t int64 `xorm:"pk autoincr"` + Name string +} + +func TestStrangeName(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(new(StrangeName)) + if err != nil { + t.Error(err) + } + + err = testEngine.CreateTables(new(StrangeName)) + if err != nil { + t.Error(err) + } + + _, err = testEngine.Insert(&StrangeName{Name: "sfsfdsfds"}) + if err != nil { + t.Error(err) + } + + beans := make([]StrangeName, 0) + err = testEngine.Find(&beans) + if err != nil { + t.Error(err) + } +} + +type CreatedUpdated struct { + Id int64 + Name string + Value float64 `xorm:"numeric"` + Created time.Time `xorm:"created"` + Created2 time.Time `xorm:"created"` + Updated time.Time `xorm:"updated"` +} + +func TestCreatedUpdated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.Sync(&CreatedUpdated{}) + if err != nil { + t.Error(err) + panic(err) + } + + c := &CreatedUpdated{Name: "test"} + _, err = testEngine.Insert(c) + if err != nil { + t.Error(err) + panic(err) + } + + c2 := new(CreatedUpdated) + has, err := testEngine.Id(c.Id).Get(c2) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + panic(errors.New("no id")) + } + + c2.Value -= 1 + _, err = testEngine.Id(c2.Id).Update(c2) + if err != nil { + t.Error(err) + panic(err) + } +} + +type Lowercase struct { + Id int64 + Name string + ended int64 `xorm:"-"` +} + +func TestLowerCase(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.Sync(&Lowercase{}) + _, err = testEngine.Where("(id) > 0").Delete(&Lowercase{}) + if err != nil { + t.Error(err) + panic(err) + } + _, err = testEngine.Insert(&Lowercase{ended: 1}) + if err != nil { + t.Error(err) + panic(err) + } + + ls := make([]Lowercase, 0) + err = testEngine.Find(&ls) + if err != nil { + t.Error(err) + panic(err) + } + + if len(ls) != 1 { + err = errors.New("should be 1") + t.Error(err) + panic(err) + } +} diff --git a/tag_version_test.go b/tag_version_test.go new file mode 100644 index 0000000..1aeabca --- /dev/null +++ b/tag_version_test.go @@ -0,0 +1,128 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +type VersionS struct { + Id int64 + Name string + Ver int `xorm:"version"` + Created time.Time `xorm:"created"` +} + +func TestVersion1(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(new(VersionS)) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(new(VersionS)) + if err != nil { + t.Error(err) + panic(err) + } + + ver := &VersionS{Name: "sfsfdsfds"} + _, err = testEngine.Insert(ver) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(ver) + if ver.Ver != 1 { + err = errors.New("insert error") + t.Error(err) + panic(err) + } + + newVer := new(VersionS) + has, err := testEngine.Id(ver.Id).Get(newVer) + if err != nil { + t.Error(err) + panic(err) + } + + if !has { + t.Error(errors.New(fmt.Sprintf("no version id is %v", ver.Id))) + panic(err) + } + fmt.Println(newVer) + if newVer.Ver != 1 { + err = errors.New("insert error") + t.Error(err) + panic(err) + } + + newVer.Name = "-------" + _, err = testEngine.Id(ver.Id).Update(newVer) + if err != nil { + t.Error(err) + panic(err) + } + if newVer.Ver != 2 { + err = errors.New("update should set version back to struct") + t.Error(err) + } + + newVer = new(VersionS) + has, err = testEngine.Id(ver.Id).Get(newVer) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(newVer) + if newVer.Ver != 2 { + err = errors.New("insert error") + t.Error(err) + panic(err) + } +} + +func TestVersion2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(new(VersionS)) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(new(VersionS)) + if err != nil { + t.Error(err) + panic(err) + } + + var vers = []VersionS{ + {Name: "sfsfdsfds"}, + {Name: "xxxxx"}, + } + _, err = testEngine.Insert(vers) + if err != nil { + t.Error(err) + panic(err) + } + + fmt.Println(vers) + + for _, v := range vers { + if v.Ver != 1 { + err := errors.New("version should be 1") + t.Error(err) + panic(err) + } + } +} diff --git a/time_test.go b/time_test.go new file mode 100644 index 0000000..fe5864d --- /dev/null +++ b/time_test.go @@ -0,0 +1,476 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestTimeUserTime(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type TimeUser struct { + Id string + OperTime time.Time + } + + assertSync(t, new(TimeUser)) + + var user = TimeUser{ + Id: "lunny", + OperTime: time.Now(), + } + + fmt.Println("user", user.OperTime) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 TimeUser + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix()) + assert.EqualValues(t, formatTime(user.OperTime), formatTime(user2.OperTime)) + fmt.Println("user2", user2.OperTime) +} + +func TestTimeUserTimeDiffLoc(t *testing.T) { + assert.NoError(t, prepareEngine()) + loc, err := time.LoadLocation("Asia/Shanghai") + assert.NoError(t, err) + testEngine.TZLocation = loc + dbLoc, err := time.LoadLocation("America/New_York") + assert.NoError(t, err) + testEngine.DatabaseTZ = dbLoc + + type TimeUser struct { + Id string + OperTime time.Time + } + + assertSync(t, new(TimeUser)) + + var user = TimeUser{ + Id: "lunny", + OperTime: time.Now(), + } + + fmt.Println("user", user.OperTime) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 TimeUser + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix()) + assert.EqualValues(t, formatTime(user.OperTime.In(loc)), formatTime(user2.OperTime)) + fmt.Println("user2", user2.OperTime) +} + +func TestTimeUserCreated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserCreated struct { + Id string + CreatedAt time.Time `xorm:"created"` + } + + assertSync(t, new(UserCreated)) + + var user = UserCreated{ + Id: "lunny", + } + + fmt.Println("user", user.CreatedAt) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 UserCreated + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + fmt.Println("user2", user2.CreatedAt) +} + +func TestTimeUserCreatedDiffLoc(t *testing.T) { + assert.NoError(t, prepareEngine()) + loc, err := time.LoadLocation("Asia/Shanghai") + assert.NoError(t, err) + testEngine.TZLocation = loc + dbLoc, err := time.LoadLocation("America/New_York") + assert.NoError(t, err) + testEngine.DatabaseTZ = dbLoc + + type UserCreated struct { + Id string + CreatedAt time.Time `xorm:"created"` + } + + assertSync(t, new(UserCreated)) + + var user = UserCreated{ + Id: "lunny", + } + + fmt.Println("user", user.CreatedAt) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 UserCreated + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + fmt.Println("user2", user2.CreatedAt) +} + +func TestTimeUserUpdated(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserUpdated struct { + Id string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` + } + + assertSync(t, new(UserUpdated)) + + var user = UserUpdated{ + Id: "lunny", + } + + fmt.Println("user", user.CreatedAt, user.UpdatedAt) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 UserUpdated + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt) + + var user3 = UserUpdated{ + Id: "lunny2", + } + + cnt, err = testEngine.Update(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix()) + + var user4 UserUpdated + has, err = testEngine.Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt)) + assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt)) + fmt.Println("user3", user.CreatedAt, user4.UpdatedAt) +} + +func TestTimeUserUpdatedDiffLoc(t *testing.T) { + assert.NoError(t, prepareEngine()) + loc, err := time.LoadLocation("Asia/Shanghai") + assert.NoError(t, err) + testEngine.TZLocation = loc + dbLoc, err := time.LoadLocation("America/New_York") + assert.NoError(t, err) + testEngine.DatabaseTZ = dbLoc + + type UserUpdated struct { + Id string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` + } + + assertSync(t, new(UserUpdated)) + + var user = UserUpdated{ + Id: "lunny", + } + + fmt.Println("user", user.CreatedAt, user.UpdatedAt) + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + var user2 UserUpdated + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt) + + var user3 = UserUpdated{ + Id: "lunny2", + } + + cnt, err = testEngine.Update(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix()) + + var user4 UserUpdated + has, err = testEngine.Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt)) + assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt)) + fmt.Println("user3", user.CreatedAt, user4.UpdatedAt) +} + +func TestTimeUserDeleted(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserDeleted struct { + Id string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` + DeletedAt time.Time `xorm:"deleted"` + } + + assertSync(t, new(UserDeleted)) + + var user = UserDeleted{ + Id: "lunny", + } + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) + + var user2 UserDeleted + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) + assert.True(t, isTimeZero(user2.DeletedAt)) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) + + var user3 UserDeleted + cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, !isTimeZero(user3.DeletedAt)) + + var user4 UserDeleted + has, err = testEngine.Unscoped().Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) + assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt)) + fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) +} + +func TestTimeUserDeletedDiffLoc(t *testing.T) { + assert.NoError(t, prepareEngine()) + loc, err := time.LoadLocation("Asia/Shanghai") + assert.NoError(t, err) + testEngine.TZLocation = loc + dbLoc, err := time.LoadLocation("America/New_York") + assert.NoError(t, err) + testEngine.DatabaseTZ = dbLoc + + type UserDeleted struct { + Id string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` + DeletedAt time.Time `xorm:"deleted"` + } + + assertSync(t, new(UserDeleted)) + + var user = UserDeleted{ + Id: "lunny", + } + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) + + var user2 UserDeleted + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) + assert.True(t, isTimeZero(user2.DeletedAt)) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) + + var user3 UserDeleted + cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, !isTimeZero(user3.DeletedAt)) + + var user4 UserDeleted + has, err = testEngine.Unscoped().Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) + assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt)) + fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) +} + +type JsonDate time.Time + +func (j JsonDate) MarshalJSON() ([]byte, error) { + if time.Time(j).IsZero() { + return []byte(`""`), nil + } + return []byte(`"` + time.Time(j).Format("2006-01-02 15:04:05") + `"`), nil +} + +func (j *JsonDate) UnmarshalJSON(value []byte) error { + var v = strings.TrimSpace(strings.Trim(string(value), "\"")) + + t, err := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local) + if err != nil { + return err + } + *j = JsonDate(t) + return nil +} + +func (j *JsonDate) Unix() int64 { + return (*time.Time)(j).Unix() +} + +func TestCustomTimeUserDeleted(t *testing.T) { + assert.NoError(t, prepareEngine()) + + type UserDeleted struct { + Id string + CreatedAt JsonDate `xorm:"created"` + UpdatedAt JsonDate `xorm:"updated"` + DeletedAt JsonDate `xorm:"deleted"` + } + + assertSync(t, new(UserDeleted)) + + var user = UserDeleted{ + Id: "lunny", + } + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) + + var user2 UserDeleted + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt))) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt))) + assert.True(t, isTimeZero(time.Time(user2.DeletedAt))) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) + + var user3 UserDeleted + cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, !isTimeZero(time.Time(user3.DeletedAt))) + + var user4 UserDeleted + has, err = testEngine.Unscoped().Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt))) + fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) +} + +func TestCustomTimeUserDeletedDiffLoc(t *testing.T) { + assert.NoError(t, prepareEngine()) + loc, err := time.LoadLocation("Asia/Shanghai") + assert.NoError(t, err) + testEngine.TZLocation = loc + dbLoc, err := time.LoadLocation("America/New_York") + assert.NoError(t, err) + testEngine.DatabaseTZ = dbLoc + + type UserDeleted struct { + Id string + CreatedAt JsonDate `xorm:"created"` + UpdatedAt JsonDate `xorm:"updated"` + DeletedAt JsonDate `xorm:"deleted"` + } + + assertSync(t, new(UserDeleted)) + + var user = UserDeleted{ + Id: "lunny", + } + + cnt, err := testEngine.Insert(&user) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) + + var user2 UserDeleted + has, err := testEngine.Get(&user2) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt))) + assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt))) + assert.True(t, isTimeZero(time.Time(user2.DeletedAt))) + fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) + + var user3 UserDeleted + cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + assert.True(t, !isTimeZero(time.Time(user3.DeletedAt))) + + var user4 UserDeleted + has, err = testEngine.Unscoped().Get(&user4) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) + assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt))) + fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) +} diff --git a/types_null_test.go b/types_null_test.go new file mode 100644 index 0000000..776b2e6 --- /dev/null +++ b/types_null_test.go @@ -0,0 +1,404 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +type NullType struct { + Id int `xorm:"pk autoincr"` + Name sql.NullString + Age sql.NullInt64 + Height sql.NullFloat64 + IsMan sql.NullBool `xorm:"null"` + CustomStruct CustomStruct `xorm:"valchar(64) null"` +} + +type CustomStruct struct { + Year int + Month int + Day int +} + +func (CustomStruct) String() string { + return "CustomStruct" +} + +func (m *CustomStruct) Scan(value interface{}) error { + if value == nil { + m.Year, m.Month, m.Day = 0, 0, 0 + return nil + } + + if s, ok := value.([]byte); ok { + seps := strings.Split(string(s), "/") + m.Year, _ = strconv.Atoi(seps[0]) + m.Month, _ = strconv.Atoi(seps[1]) + m.Day, _ = strconv.Atoi(seps[2]) + return nil + } + + return errors.New("scan data not fit []byte") +} + +func (m CustomStruct) Value() (driver.Value, error) { + return fmt.Sprintf("%d/%d/%d", m.Year, m.Month, m.Day), nil +} + +func TestCreateNullStructTable(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.CreateTables(new(NullType)) + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestDropNullStructTable(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(new(NullType)) + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestNullStructInsert(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + if true { + item := new(NullType) + _, err := testEngine.Insert(item) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(item) + if item.Id != 1 { + err = errors.New("insert error") + t.Error(err) + panic(err) + } + } + + if true { + item := NullType{ + Name: sql.NullString{"haolei", true}, + Age: sql.NullInt64{34, true}, + Height: sql.NullFloat64{1.72, true}, + IsMan: sql.NullBool{true, true}, + } + _, err := testEngine.Insert(&item) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(item) + if item.Id != 2 { + err = errors.New("insert error") + t.Error(err) + panic(err) + } + } + + if true { + items := []NullType{} + + for i := 0; i < 5; i++ { + item := NullType{ + Name: sql.NullString{"haolei_" + fmt.Sprint(i+1), true}, + Age: sql.NullInt64{30 + int64(i), true}, + Height: sql.NullFloat64{1.5 + 1.1*float64(i), true}, + IsMan: sql.NullBool{true, true}, + CustomStruct: CustomStruct{i, i + 1, i + 2}, + } + + items = append(items, item) + } + + _, err := testEngine.Insert(&items) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(items) + } +} + +func TestNullStructUpdate(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + _, err := testEngine.Insert([]NullType{ + { + Name: sql.NullString{ + String: "name1", + Valid: true, + }, + }, + { + Name: sql.NullString{ + String: "name2", + Valid: true, + }, + }, + { + Name: sql.NullString{ + String: "name3", + Valid: true, + }, + }, + { + Name: sql.NullString{ + String: "name4", + Valid: true, + }, + }, + }) + assert.NoError(t, err) + + if true { // 测试可插入NULL + item := new(NullType) + item.Age = sql.NullInt64{23, true} + item.Height = sql.NullFloat64{0, false} // update to NULL + + affected, err := testEngine.Id(2).Cols("age", "height", "is_man").Update(item) + if err != nil { + t.Error(err) + panic(err) + } + if affected != 1 { + err := errors.New("update failed") + t.Error(err) + panic(err) + } + } + + if true { // 测试In update + item := new(NullType) + item.Age = sql.NullInt64{23, true} + affected, err := testEngine.In("id", 3, 4).Cols("age", "height", "is_man").Update(item) + if err != nil { + t.Error(err) + panic(err) + } + if affected != 2 { + err := errors.New("update failed") + t.Error(err) + panic(err) + } + } + + if true { // 测试where + item := new(NullType) + item.Name = sql.NullString{"nullname", true} + item.IsMan = sql.NullBool{true, true} + item.Age = sql.NullInt64{34, true} + + _, err := testEngine.Where("age > ?", 34).Update(item) + if err != nil { + t.Error(err) + panic(err) + } + } + + if true { // 修改全部时,插入空值 + item := &NullType{ + Name: sql.NullString{"winxxp", true}, + Age: sql.NullInt64{30, true}, + Height: sql.NullFloat64{1.72, true}, + // IsMan: sql.NullBool{true, true}, + } + + _, err := testEngine.AllCols().Id(6).Update(item) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(item) + } + +} + +func TestNullStructFind(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + _, err := testEngine.Insert([]NullType{ + { + Name: sql.NullString{ + String: "name1", + Valid: false, + }, + }, + { + Name: sql.NullString{ + String: "name2", + Valid: true, + }, + }, + { + Name: sql.NullString{ + String: "name3", + Valid: true, + }, + }, + { + Name: sql.NullString{ + String: "name4", + Valid: true, + }, + }, + }) + assert.NoError(t, err) + + if true { + item := new(NullType) + has, err := testEngine.Id(1).Get(item) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + t.Error(errors.New("no find id 1")) + panic(err) + } + fmt.Println(item) + if item.Id != 1 || item.Name.Valid || item.Age.Valid || item.Height.Valid || + item.IsMan.Valid { + err = errors.New("insert error") + t.Error(err) + panic(err) + } + } + + if true { + item := new(NullType) + item.Id = 2 + + has, err := testEngine.Get(item) + if err != nil { + t.Error(err) + panic(err) + } + if !has { + t.Error(errors.New("no find id 2")) + panic(err) + } + fmt.Println(item) + } + + if true { + item := make([]NullType, 0) + + err := testEngine.Id(2).Find(&item) + if err != nil { + t.Error(err) + panic(err) + } + + fmt.Println(item) + } + + if true { + item := make([]NullType, 0) + + err := testEngine.Asc("age").Find(&item) + if err != nil { + t.Error(err) + panic(err) + } + + for k, v := range item { + fmt.Println(k, v) + } + } +} + +func TestNullStructIterate(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + if true { + err := testEngine.Where("age IS NOT NULL").OrderBy("age").Iterate(new(NullType), + func(i int, bean interface{}) error { + nultype := bean.(*NullType) + fmt.Println(i, nultype) + return nil + }) + if err != nil { + t.Error(err) + panic(err) + } + } +} + +func TestNullStructCount(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + if true { + item := new(NullType) + total, err := testEngine.Where("age IS NOT NULL").Count(item) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(total) + } +} + +func TestNullStructRows(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + item := new(NullType) + rows, err := testEngine.Where("id > ?", 1).Rows(item) + if err != nil { + t.Error(err) + panic(err) + } + defer rows.Close() + + for rows.Next() { + err = rows.Scan(item) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(item) + } +} + +func TestNullStructDelete(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(NullType)) + + item := new(NullType) + + _, err := testEngine.Id(1).Delete(item) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = testEngine.Where("id > ?", 1).Delete(item) + if err != nil { + t.Error(err) + panic(err) + } +} diff --git a/types_test.go b/types_test.go index 900dac9..7c2ff67 100644 --- a/types_test.go +++ b/types_test.go @@ -5,9 +5,13 @@ package xorm import ( + "encoding/json" + "errors" + "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/xormplus/core" ) func TestArrayField(t *testing.T) { @@ -95,3 +99,237 @@ func TestGetBytes(t *testing.T) { assert.Equal(t, true, has) assert.Equal(t, "test", string(b.Data)) } + +type ConvString string + +func (s *ConvString) FromDB(data []byte) error { + *s = ConvString("prefix---" + string(data)) + return nil +} + +func (s *ConvString) ToDB() ([]byte, error) { + return []byte(string(*s)), nil +} + +type ConvConfig struct { + Name string + Id int64 +} + +func (s *ConvConfig) FromDB(data []byte) error { + return json.Unmarshal(data, s) +} + +func (s *ConvConfig) ToDB() ([]byte, error) { + return json.Marshal(s) +} + +type SliceType []*ConvConfig + +func (s *SliceType) FromDB(data []byte) error { + return json.Unmarshal(data, s) +} + +func (s *SliceType) ToDB() ([]byte, error) { + return json.Marshal(s) +} + +type ConvStruct struct { + Conv ConvString + Conv2 *ConvString + Cfg1 ConvConfig + Cfg2 *ConvConfig `xorm:"TEXT"` + Cfg3 core.Conversion `xorm:"BLOB"` + Slice SliceType +} + +func (c *ConvStruct) BeforeSet(name string, cell Cell) { + if name == "cfg3" || name == "Cfg3" { + c.Cfg3 = new(ConvConfig) + } +} + +func TestConversion(t *testing.T) { + assert.NoError(t, prepareEngine()) + + c := new(ConvStruct) + assert.NoError(t, testEngine.DropTables(c)) + assert.NoError(t, testEngine.Sync(c)) + + var s ConvString = "sssss" + c.Conv = "tttt" + c.Conv2 = &s + c.Cfg1 = ConvConfig{"mm", 1} + c.Cfg2 = &ConvConfig{"xx", 2} + c.Cfg3 = &ConvConfig{"zz", 3} + c.Slice = []*ConvConfig{{"yy", 4}, {"ff", 5}} + + _, err := testEngine.Insert(c) + assert.NoError(t, err) + + c1 := new(ConvStruct) + has, err := testEngine.Get(c1) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, "prefix---tttt", string(c1.Conv)) + assert.NotNil(t, c1.Conv2) + assert.EqualValues(t, "prefix---"+s, *c1.Conv2) + assert.EqualValues(t, c.Cfg1, c1.Cfg1) + assert.NotNil(t, c1.Cfg2) + assert.EqualValues(t, *c.Cfg2, *c1.Cfg2) + assert.NotNil(t, c1.Cfg3) + assert.EqualValues(t, *c.Cfg3.(*ConvConfig), *c1.Cfg3.(*ConvConfig)) + assert.EqualValues(t, 2, len(c1.Slice)) + assert.EqualValues(t, *c.Slice[0], *c1.Slice[0]) + assert.EqualValues(t, *c.Slice[1], *c1.Slice[1]) +} + +type MyInt int +type MyUInt uint +type MyFloat float64 + +type MyStruct struct { + Type MyInt + U MyUInt + F MyFloat + S MyString + IA []MyInt + UA []MyUInt + FA []MyFloat + SA []MyString + NameArray []string + Name string + UIA []uint + UIA8 []uint8 + UIA16 []uint16 + UIA32 []uint32 + UIA64 []uint64 + UI uint + //C64 complex64 + MSS map[string]string +} + +func TestCustomType1(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&MyStruct{}) + assert.NoError(t, err) + + err = testEngine.CreateTables(&MyStruct{}) + assert.NoError(t, err) + + i := MyStruct{Name: "Test", Type: MyInt(1)} + i.U = 23 + i.F = 1.34 + i.S = "fafdsafdsaf" + i.UI = 2 + i.IA = []MyInt{1, 3, 5} + i.UIA = []uint{1, 3} + i.UIA16 = []uint16{2} + i.UIA32 = []uint32{4, 5} + i.UIA64 = []uint64{6, 7, 9} + i.UIA8 = []uint8{1, 2, 3, 4} + i.NameArray = []string{"ssss", "fsdf", "lllll, ss"} + i.MSS = map[string]string{"s": "sfds,ss", "x": "lfjljsl"} + + cnt, err := testEngine.Insert(&i) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + fmt.Println(i) + i.NameArray = []string{} + i.MSS = map[string]string{} + i.F = 0 + has, err := testEngine.Get(&i) + assert.NoError(t, err) + assert.True(t, has) + + ss := []MyStruct{} + err = testEngine.Find(&ss) + assert.NoError(t, err) + assert.EqualValues(t, 1, len(ss)) + assert.EqualValues(t, i, ss[0]) + + sss := MyStruct{} + has, err = testEngine.Get(&sss) + assert.NoError(t, err) + assert.True(t, has) + + sss.NameArray = []string{} + sss.MSS = map[string]string{} + cnt, err = testEngine.Delete(&sss) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) +} + +type Status struct { + Name string + Color string +} + +var ( + _ core.Conversion = &Status{} + Registed Status = Status{"Registed", "white"} + Approved Status = Status{"Approved", "green"} + Removed Status = Status{"Removed", "red"} + Statuses map[string]Status = map[string]Status{ + Registed.Name: Registed, + Approved.Name: Approved, + Removed.Name: Removed, + } +) + +func (s *Status) FromDB(bytes []byte) error { + if r, ok := Statuses[string(bytes)]; ok { + *s = r + return nil + } else { + return errors.New("no this data") + } +} + +func (s *Status) ToDB() ([]byte, error) { + return []byte(s.Name), nil +} + +type UserCus struct { + Id int64 + Name string + Status Status `xorm:"varchar(40)"` +} + +func TestCustomType2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.CreateTables(&UserCus{}) + assert.NoError(t, err) + + tableName := testEngine.TableMapper.Obj2Table("UserCus") + _, err = testEngine.Exec("delete from " + testEngine.Quote(tableName)) + assert.NoError(t, err) + + if testEngine.Dialect().DBType() == core.MSSQL { + return + /*_, err = engine.Exec("set IDENTITY_INSERT " + tableName + " on") + if err != nil { + t.Fatal(err) + }*/ + } + + _, err = testEngine.Insert(&UserCus{1, "xlw", Registed}) + assert.NoError(t, err) + + user := UserCus{} + exist, err := testEngine.Id(1).Get(&user) + assert.NoError(t, err) + assert.True(t, exist) + + fmt.Println(user) + + users := make([]UserCus, 0) + err = testEngine.Where("`"+testEngine.ColumnMapper.Obj2Table("Status")+"` = ?", "Registed").Find(&users) + assert.NoError(t, err) + assert.EqualValues(t, 1, len(users)) + + fmt.Println(users) +} diff --git a/xorm_test.go b/xorm_test.go index 98b42b6..2e722f8 100644 --- a/xorm_test.go +++ b/xorm_test.go @@ -4,15 +4,19 @@ import ( "flag" "fmt" "os" + "strings" "testing" + _ "github.com/denisenkom/go-mssqldb" _ "github.com/go-sql-driver/mysql" + "github.com/go-xorm/core" _ "github.com/lib/pq" _ "github.com/mattn/go-sqlite3" ) var ( testEngine *Engine + dbType string connString string db = flag.String("db", "sqlite3", "the tested database") @@ -31,6 +35,7 @@ func createEngine(dbType, connStr string) error { } testEngine.ShowSQL(*showSQL) + testEngine.logger.SetLevel(core.LOG_DEBUG) } tables, err := testEngine.DBMetas() @@ -41,19 +46,23 @@ func createEngine(dbType, connStr string) error { for _, table := range tables { tableNames = append(tableNames, table.Name) } - return testEngine.DropTables(tableNames...) + if err = testEngine.DropTables(tableNames...); err != nil { + return err + } + return nil } func prepareEngine() error { - return createEngine(*db, connString) + return createEngine(dbType, connString) } func TestMain(m *testing.M) { flag.Parse() + dbType = *db if *db == "sqlite3" { if ptrConnStr == nil { - connString = "./test.db" + connString = "./test.db?cache=shared&mode=rwc" } else { connString = *ptrConnStr } @@ -65,11 +74,28 @@ func TestMain(m *testing.M) { connString = *ptrConnStr } - if err := prepareEngine(); err != nil { - fmt.Println(err) - return + dbs := strings.Split(*db, "::") + conns := strings.Split(connString, "::") + + var res int + for i := 0; i < len(dbs); i++ { + dbType = dbs[i] + connString = conns[i] + testEngine = nil + fmt.Println("testing", dbType, connString) + + if err := prepareEngine(); err != nil { + fmt.Println(err) + return + } + + code := m.Run() + if code > 0 { + res = code + } } - os.Exit(m.Run()) + + os.Exit(res) } func TestPing(t *testing.T) {