From 68e64d101ee8e463689d127ddb61cd480adc2c06 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 Jan 2014 16:57:05 +0800 Subject: [PATCH 01/41] improved test --- base_test.go | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/base_test.go b/base_test.go index 37532250..eba9d3bc 100644 --- a/base_test.go +++ b/base_test.go @@ -557,20 +557,48 @@ func where(engine *Engine, t *testing.T) { func in(engine *Engine, t *testing.T) { users := make([]Userinfo, 0) - err := engine.In("(id)", 1, 2, 3).Find(&users) + err := engine.In("(id)", 7, 8, 9).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + if len(users) != 3 { + err = errors.New("in uses should be 7,8,9 total 3") + t.Error(err) + panic(err) + } + + for _, user := range users { + if user.Uid != 7 && user.Uid != 8 && user.Uid != 9 { + err = errors.New("in uses should be 7,8,9 total 3") + t.Error(err) + panic(err) + } + } + + users = make([]Userinfo, 0) + ids := []interface{}{7, 8, 9} + err = engine.Where("departname = ?", "dev").In("(id)", ids...).Find(&users) if err != nil { t.Error(err) panic(err) } fmt.Println(users) - ids := []interface{}{1, 2, 3} - err = engine.Where("(id) > ?", 2).In("(id)", ids...).Find(&users) - if err != nil { + if len(users) != 3 { + err = errors.New("in uses should be 7,8,9 total 3") t.Error(err) panic(err) } - fmt.Println(users) + + for _, user := range users { + if user.Uid != 7 && user.Uid != 8 && user.Uid != 9 { + err = errors.New("in uses should be 7,8,9 total 3") + t.Error(err) + panic(err) + } + } err = engine.In("(id)", 1).In("(id)", 2).In("departname", "dev").Find(&users) if err != nil { From adb8edb323d17ac7ac85ddfa1d1259b04b64361c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 15 Jan 2014 10:31:14 +0800 Subject: [PATCH 02/41] improved docs --- docs/QuickStart.md | 64 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 719269e5..d77ee672 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -63,7 +63,7 @@ defer engine.Close() 一般如果只针对一个数据库进行操作,只需要创建一个Engine即可。Engine支持在多GoRutine下使用。 -xorm当前支持四种驱动如下: +xorm当前支持五种驱动四个数据库如下: * Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) @@ -110,7 +110,7 @@ xorm支持将一个struct映射为数据库中对应的一张表。映射规则 ### 2.1.名称映射规则 -名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射。由xorm.IMapper接口的实现者来管理,xorm内置了两种IMapper实现:`SnakeMapper` 和 `SameMapper`。SnakeMapper支持struct为驼峰式命名,表结构为下划线命名之间的转换;SameMapper支持相同的命名。 +名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射。由xorm.IMapper接口的实现者来管理,xorm内置了两种IMapper实现:`SnakeMapper` 和 `SameMapper`。SnakeMapper支持struct为驼峰式命名,表结构为下划线命名之间的转换;SameMapper支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名。 当前SnakeMapper为默认值,如果需要改变时,在engine创建完成后使用 @@ -121,7 +121,8 @@ engine.SetMapper(SameMapper{}) 同时需要注意的是: * 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 -* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: +* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: + ```Go engine.SetTableMapper(SameMapper{}) engine.SetColumnMapper(SnakeMapper{}) @@ -130,8 +131,9 @@ engine.SetColumnMapper(SnakeMapper{}) ### 2.2.前缀映射规则和后缀映射规则 -* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀; -* 通过`engine.NewSufffixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的后缀。 +* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 +* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 +* ### 2.3.使用Table和Tag改变名称映射 @@ -160,7 +162,7 @@ type User struct { name当前field对应的字段的名称,可选,如不写,则自动根据field名字和转换规则命名,如与其它关键字冲突,请使用单引号括起来。 - pk是否是Primary Key,如果在一个struct中有两个字段都使用了此标记,则这两个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7中Go的数据类型。 + pk是否是Primary Key,如果在一个struct中有多个字段都使用了此标记,则这多个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7种Go的数据类型,复合主键支持这7种Go的数据类型的组合。 当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)字段类型 @@ -205,7 +207,7 @@ type User struct { 另外有如下几条自动映射的规则: -- 1.如果field名称为`Id`而且类型为`int64`的话,会被xorm视为主键,并且拥有自增属性。如果想用`Id`以外的名字或非int64类型做为主键名,必须在对应的Tag上加上`xorm:"pk"`来定义主键,加上`xorm:"autoincr"`作为自增。这里需要注意的是,有些数据库并不允许非主键的自增属性。 +- 1.如果field名称为`Id`而且类型为`int64`并且没有定义tag,则会被xorm视为主键,并且拥有自增属性。如果想用`Id`以外的名字或非int64类型做为主键名,必须在对应的Tag上加上`xorm:"pk"`来定义主键,加上`xorm:"autoincr"`作为自增。这里需要注意的是,有些数据库并不允许非主键的自增属性。 - 2.string类型默认映射为varchar(255),如果需要不同的定义,可以在tag中自定义 @@ -235,41 +237,50 @@ xorm提供了一些动态获取和修改表结构的方法。对于一般的应 ## 3.1 获取数据库信息 * DBMetas() + xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到所有的表,字段,索引的信息。 ## 3.2.表操作 * CreateTables() + 创建表使用`engine.CreateTables()`,参数为一个或多个空的对应Struct的指针。同时可用的方法有Charset()和StoreEngine(),如果对应的数据库支持,这两个方法可以在创建表时指定表的字符编码和使用的引擎。当前仅支持Mysql数据库。 * IsTableEmpty() + 判断表是否为空,参数和CreateTables相同 * IsTableExist() + 判断表是否存在 * DropTables() + 删除表使用`engine.DropTables()`,参数为一个或多个空的对应Struct的指针或者表的名字。如果为string传入,则只删除对应的表,如果传入的为Struct,则删除表的同时还会删除对应的索引。 ## 3.3.创建索引和唯一索引 * CreateIndexes + 根据struct中的tag来创建索引 * CreateUniques + 根据struct中的tag来创建唯一索引 ## 3.4.同步数据库结构 同步能够部分智能的根据结构体的变动检测表结构的变动,并自动同步。目前能够实现: -1) 自动检测和创建表,这个检测是根据表的名字 -2)自动检测和新增表中的字段,这个检测是根据字段名 -3)自动检测和创建索引和唯一索引,这个检测是根据一个或多个字段名,而不根据索引名称 + +* 1) 自动检测和创建表,这个检测是根据表的名字 +* 2)自动检测和新增表中的字段,这个检测是根据字段名 +* 3)自动检测和创建索引和唯一索引,这个检测是根据一个或多个字段名,而不根据索引名称 调用方法如下: + ```Go err := engine.Sync(new(User)) ``` @@ -281,6 +292,7 @@ err := engine.Sync(new(User)) 如果传入的是Slice并且当数据库支持批量插入时,Insert会使用批量插入的方式进行插入。 * 插入一条数据 + ```Go user := new(User) user.Name = "myname" @@ -288,11 +300,13 @@ affected, err := engine.Insert(user) ``` 在插入单条数据成功后,如果该结构体有自增字段,则自增字段会被自动赋值为数据库中的id + ```Go fmt.Println(user.Id) ``` * 插入同一个表的多条数据 + ```Go users := make([]User, 0) users[0].Name = "name0" @@ -301,6 +315,7 @@ affected, err := engine.Insert(&users) ``` * 使用指针Slice插入多条记录 + ```Go users := make([]*User, 0) users[0] = new(User) @@ -310,6 +325,7 @@ affected, err := engine.Insert(&users) ``` * 插入不同表的一条记录 + ```Go user := new(User) user.Name = "myname" @@ -319,6 +335,7 @@ affected, err := engine.Insert(user, question) ``` * 插入不同表的多条记录 + ```Go users := make([]User, 0) users[0].Name = "name0" @@ -355,10 +372,10 @@ affected, err := engine.Insert(user, &questions) * Id(interface{}) 传入一个PK字段的值,作为查询条件,如果是复合主键,则 `Id(xorm.PK{1, 2})` -传入的两个参数按照struct中字段出现的顺序赋值。 +传入的两个参数按照struct中pk标记字段出现的顺序赋值。 * Where(string, …interface{}) -和Where语句中的条件基本相同,作为条件 +和SQL中Where语句中的条件基本相同,作为条件 * And(string, …interface{}) 和Where函数中的条件基本相同,作为条件 @@ -379,7 +396,7 @@ affected, err := engine.Insert(user, &questions) 按照指定的顺序进行排序 * In(string, …interface{}) -某字段在一些值中 +某字段在一些值中,这里需要注意必须是[]interface{}才可以展开,由于Go语言的限制,[]int64等均不可以展开。 * Cols(…string) 只查询或更新某些指定的字段,默认是查询所有映射的字段或者根据Update的第一个参数来判断更新的字段。例如: @@ -448,20 +465,28 @@ Having的参数字符串 如: 1) 根据Id来获得单条数据: + ```Go user := new(User) has, err := engine.Id(id).Get(user) +// 复合主键的获取方法 +// has, errr := engine.Id(xorm.PK{1,2}).Get(user) ``` + 2) 根据Where来获得单条数据: + ```Go user := new(User) has, err := engine.Where("name=?", "xlw").Get(user) ``` + 3) 根据user结构体中已有的非空数据来获得单条数据: + ```Go user := &User{Id:1} has, err := engine.Get(user) ``` + 或者其它条件 ```Go @@ -477,6 +502,7 @@ has, err := engine.Get(user) 查询多条数据使用`Find`方法,Find方法的第一个参数为`slice`的指针或`Map`指针,即为查询后返回的结果,第二个参数可选,为查询的条件struct的指针。 1) 传入Slice用于返回数据 + ```Go everyone := make([]Userinfo, 0) err := engine.Find(&everyone) @@ -485,7 +511,8 @@ pEveryOne := make([]*Userinfo, 0) err := engine.Find(&pEveryOne) ``` -2) 传入Map用户返回数据,map必须为`map[int64]Userinfo`的形式,map的key为id +2) 传入Map用户返回数据,map必须为`map[int64]Userinfo`的形式,map的key为id,因此对于复合主键无法使用这种方式。 + ```Go users := make(map[int64]Userinfo) err := engine.Find(&users) @@ -495,6 +522,7 @@ err := engine.Find(&pUsers) ``` 3) 也可以加入各种条件 + ```Go users := make([]Userinfo, 0) err := engine.Where("age > ? or name = ?", 30, "xlw").Limit(20, 10).Find(&users) @@ -504,6 +532,7 @@ err := engine.Where("age > ? or name = ?", 30, "xlw").Limit(20, 10).Find(&users) ### 5.5.Iterate方法 Iterate方法提供逐条执行查询到的记录的方法,他所能使用的条件和Find方法完全相同 + ```Go err := engine.Where("age > ? or name=?)", 30, "xlw").Iterate(new(Userinfo), func(i int, bean interface{})error{ user := bean.(*Userinfo) @@ -550,11 +579,13 @@ affected, err := engine.Id(id).Update(user) 这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择: 1. 通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 + ```Go affected, err := engine.Id(id).Cols("age").Update(&user) ``` 2. 通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 + ```Go affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0}) ``` @@ -583,6 +614,7 @@ engine.Id(1).Update(&user) ## 7.删除数据 删除数据`Delete`方法,参数为struct的指针并且成为查询条件。 + ```Go user := new(User) affected, err := engine.Id(id).Delete(user) @@ -659,14 +691,17 @@ xorm内置了一致性缓存支持,不过默认并没有开启。要开启缓 cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) engine.SetDefaultCacher(cacher) ``` + 上述代码采用了LRU算法的一个缓存,缓存方式是存放到内存中,缓存struct的记录数为1000条,缓存针对的范围是所有具有主键的表,没有主键的表中的数据将不会被缓存。 如果只想针对部分表,则: + ```Go cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) engine.MapCacher(&user, cacher) ``` 如果要禁用某个表的缓存,则: + ```Go engine.MapCacher(&user, nil) ``` @@ -682,6 +717,7 @@ engine.MapCacher(&user, nil) 2. 在`Get`或者`Find`时使用了`Cols`,`Omit`方法,则在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。 3. 在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。比如: + ```Go engine.Exec("update user set name = ? where id = ?", "xlw", 1) engine.ClearCache(new(User)) From 004974d44dd370035db0cc9d06b359b13fe47460 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 15 Jan 2014 10:34:41 +0800 Subject: [PATCH 03/41] improved docs --- docs/QuickStart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/QuickStart.md b/docs/QuickStart.md index d77ee672..6fc55f7b 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -578,13 +578,13 @@ affected, err := engine.Id(id).Update(user) 这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择: -1. 通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 +* 1.通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 ```Go affected, err := engine.Id(id).Cols("age").Update(&user) ``` -2. 通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 +* 2.通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 ```Go affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0}) From 6147651a6e1e8541a81eb4bcf2157b7e52d99fda Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 15 Jan 2014 10:39:16 +0800 Subject: [PATCH 04/41] bug fixed --- table.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/table.go b/table.go index e63db20e..76b4c3ae 100644 --- a/table.go +++ b/table.go @@ -298,6 +298,8 @@ func (col *Column) String(d dialect) string { if col.Default != "" { sql += "DEFAULT " + col.Default + " " + } else if col.IsVersion { + sql += "DEFAULT 1 " } return sql @@ -316,6 +318,8 @@ func (col *Column) stringNoPk(d dialect) string { if col.Default != "" { sql += "DEFAULT " + col.Default + " " + } else if col.IsVersion { + sql += "DEFAULT 1 " } return sql From 346681289d6b5ee80b48a7a33e59f4597fea1b9e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 16 Jan 2014 23:03:56 +0800 Subject: [PATCH 05/41] bug fixed #51 --- base_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ engine.go | 7 +++++-- postgres.go | 2 +- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/base_test.go b/base_test.go index eba9d3bc..c5d88c86 100644 --- a/base_test.go +++ b/base_test.go @@ -267,6 +267,16 @@ func insertTwoTable(engine *Engine, t *testing.T) { } } +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)"` +} + type Condi map[string]interface{} func update(engine *Engine, t *testing.T) { @@ -314,6 +324,44 @@ func update(engine *Engine, t *testing.T) { panic(err) return } + + err = engine.Sync(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + + cnt, err = engine.Insert(&Article{0, "1", "2", "3", "4", "5", 2}) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New("insert not returned 1") + t.Error(err) + panic(err) + return + } + + cnt, err = engine.Id(1).Update(&Article{Name: "6"}) + if err != nil { + t.Error(err) + panic(err) + } + + if cnt != 1 { + err = errors.New("update not returned 1") + t.Error(err) + panic(err) + return + } + + err = engine.DropTables(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } } func updateSameMapper(engine *Engine, t *testing.T) { diff --git a/engine.go b/engine.go index b5fd317f..93494048 100644 --- a/engine.go +++ b/engine.go @@ -482,6 +482,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } var indexType int var indexName string + var preKey string for j, key := range tags { k := strings.ToUpper(key) switch { @@ -520,12 +521,13 @@ func (engine *Engine) mapType(t reflect.Type) *Table { case k == "NOT": default: if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") { - if key != col.Default { + if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { + preKey = k continue } col.SQLType = SQLType{fs[0], 0, 0} @@ -539,12 +541,13 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } else { if _, ok := sqlTypes[k]; ok { col.SQLType = SQLType{k, 0, 0} - } else if key != col.Default { + } else if preKey != "DEFAULT" { col.Name = key } } engine.SqlType(col) } + preKey = k } if col.SQLType.Name == "" { col.SQLType = Type2SQLType(fieldType) diff --git a/postgres.go b/postgres.go index 9e12b009..97550543 100644 --- a/postgres.go +++ b/postgres.go @@ -67,7 +67,7 @@ func (db *postgres) SqlType(c *Column) string { switch t := c.SQLType.Name; t { case TinyInt: res = SmallInt - + return res case MediumInt, Int, Integer: if c.IsAutoIncrement { return Serial From 19b0a57dcd52278686dd2c0fc3f0bebe808e2b6b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 21 Jan 2014 22:22:06 +0800 Subject: [PATCH 06/41] add lowertest --- base_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ session.go | 1 + 2 files changed, 43 insertions(+) diff --git a/base_test.go b/base_test.go index d2ea0606..b10643a4 100644 --- a/base_test.go +++ b/base_test.go @@ -3334,6 +3334,45 @@ func testCompositeKey(engine *Engine, t *testing.T) { } } +type Lowercase struct { + Id int64 + Name string + ended int64 `xorm:"-"` +} + +func testLowerCase(engine *Engine, t *testing.T) { + err := engine.Sync(&Lowercase{}) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = engine.Where("id > 0").Delete(&Lowercase{}) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = engine.Insert(&Lowercase{ended: 1}) + if err != nil { + t.Error(err) + panic(err) + } + + ls := make([]Lowercase, 0) + err = engine.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) + } +} + func testAll(engine *Engine, t *testing.T) { fmt.Println("-------------- directCreateTable --------------") directCreateTable(engine, t) @@ -3430,6 +3469,8 @@ func testAll2(engine *Engine, t *testing.T) { testPrefixTableName(engine, t) fmt.Println("-------------- testCreatedUpdated --------------") testCreatedUpdated(engine, t) + fmt.Println("-------------- testLowercase ---------------") + testLowerCase(engine, t) fmt.Println("-------------- processors --------------") testProcessors(engine, t) fmt.Println("-------------- transaction --------------") @@ -3446,4 +3487,5 @@ func testAll3(engine *Engine, t *testing.T) { testNullValue(engine, t) fmt.Println("-------------- testCompositeKey --------------") testCompositeKey(engine, t) + } diff --git a/session.go b/session.go index 3840c721..9c0c4b22 100644 --- a/session.go +++ b/session.go @@ -2153,6 +2153,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } colPlaces := strings.Repeat("?, ", len(colNames)) + fmt.Println(colNames, args) colPlaces = colPlaces[0 : len(colPlaces)-2] sql := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)", From 2699e20b7b57fc48dff678347a4a873cc177daf7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 21 Jan 2014 23:23:53 +0800 Subject: [PATCH 07/41] add case gocms --- README.md | 2 ++ README_CN.md | 3 +++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index ecdfa721..85e5d46c 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,8 @@ Or * [Very Hour](http://veryhour.com/) +* [GoCMS](https://github.com/zzdboy/GoCMS) + # Todo [Todo List](https://trello.com/b/IHsuAnhk/xorm) diff --git a/README_CN.md b/README_CN.md index d1b88e67..8088f423 100644 --- a/README_CN.md +++ b/README_CN.md @@ -87,6 +87,9 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 * [Very Hour](http://veryhour.com/) +* [GoCMS](https://github.com/zzdboy/GoCMS) + + ## Todo [开发计划](https://trello.com/b/IHsuAnhk/xorm) From d71a6af18a09591079a7a385d8db1b1cb29fd427 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 23 Jan 2014 10:19:18 +0800 Subject: [PATCH 08/41] autoincr(start) support --- engine.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/engine.go b/engine.go index 93494048..1f2312de 100644 --- a/engine.go +++ b/engine.go @@ -452,6 +452,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { table.Type = t var idFieldColName string + var err error for i := 0; i < t.NumField(); i++ { tag := t.Field(i).Tag @@ -495,8 +496,18 @@ func (engine *Engine) mapType(t reflect.Type) *Table { col.Nullable = false case k == "NULL": col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT") + /*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"): + col.IsAutoIncrement = true + + autoStart := k[len("AUTOINCR")+1 : len(k)-1] + autoStartInt, err := strconv.Atoi(autoStart) + if err != nil { + engine.LogError(err) + } + col.AutoIncrStart = autoStartInt*/ case k == "AUTOINCR": col.IsAutoIncrement = true + //col.AutoIncrStart = 1 case k == "DEFAULT": col.Default = tags[j+1] case k == "CREATED": @@ -533,10 +544,19 @@ func (engine *Engine) mapType(t reflect.Type) *Table { col.SQLType = SQLType{fs[0], 0, 0} fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",") if len(fs2) == 2 { - col.Length, _ = strconv.Atoi(fs2[0]) - col.Length2, _ = strconv.Atoi(fs2[1]) + col.Length, err = strconv.Atoi(fs2[0]) + if err != nil { + engine.LogError(err) + } + col.Length2, err = strconv.Atoi(fs2[1]) + if err != nil { + engine.LogError(err) + } } else if len(fs2) == 1 { - col.Length, _ = strconv.Atoi(fs2[0]) + col.Length, err = strconv.Atoi(fs2[0]) + if err != nil { + engine.LogError(err) + } } } else { if _, ok := sqlTypes[k]; ok { From 42e5fb880f44a648eb5056e45ae8b7c99c72f4e7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 24 Jan 2014 09:07:10 +0800 Subject: [PATCH 09/41] comment debug info --- session.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session.go b/session.go index bd647de6..75570fcd 100644 --- a/session.go +++ b/session.go @@ -2475,7 +2475,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } colPlaces := strings.Repeat("?, ", len(colNames)) - fmt.Println(colNames, args) + //fmt.Println(colNames, args) colPlaces = colPlaces[0 : len(colPlaces)-2] sqlStr := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)", From 9e267ad5c3ce8c493c11a41b2c95d63cabee34bf Mon Sep 17 00:00:00 2001 From: "S.W.H" Date: Mon, 27 Jan 2014 21:25:49 +0800 Subject: [PATCH 10/41] fixbug: parse DECIMAL(10, 2) failure. --- engine.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engine.go b/engine.go index 1f2312de..e0aa2bf2 100644 --- a/engine.go +++ b/engine.go @@ -484,7 +484,8 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j, key := range tags { + for j,ln := 0,len(tags); j < ln; j++ { + key := tags[j] k := strings.ToUpper(key) switch { case k == "<-": @@ -535,7 +536,18 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { + } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { + //[SWH|+] + if strings.HasSuffix(k, ",") { + j++ + for j < ln { + k += tags[j] + if strings.HasSuffix(tags[j], ")") { + break + } + j++ + } + } fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k From d4f8196920edb632b625f70526a456495e556117 Mon Sep 17 00:00:00 2001 From: "S.W.H" Date: Mon, 27 Jan 2014 21:28:13 +0800 Subject: [PATCH 11/41] fixbug: parse DECIMAL(10, 2) failure. --- engine.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engine.go b/engine.go index 1f2312de..e0aa2bf2 100644 --- a/engine.go +++ b/engine.go @@ -484,7 +484,8 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j, key := range tags { + for j,ln := 0,len(tags); j < ln; j++ { + key := tags[j] k := strings.ToUpper(key) switch { case k == "<-": @@ -535,7 +536,18 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { + } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { + //[SWH|+] + if strings.HasSuffix(k, ",") { + j++ + for j < ln { + k += tags[j] + if strings.HasSuffix(tags[j], ")") { + break + } + j++ + } + } fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k From 46fe2ce87ed20148720734f0b642a179b86337c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=95=86=E8=AE=AF=E5=9C=A8=E7=BA=BF?= Date: Thu, 30 Jan 2014 13:10:15 +0800 Subject: [PATCH 12/41] =?UTF-8?q?=E4=B8=80=E3=80=81xorm=E5=8F=8D=E8=BD=AC?= =?UTF-8?q?=E5=B7=A5=E5=85=B7bug=E4=BF=AE=E5=A4=8D=EF=BC=9A=201=E3=80=81xo?= =?UTF-8?q?rm=E5=8F=8D=E8=BD=AC=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=A1=A8=E5=89=8D=E7=BC=80=E6=94=AF=E6=8C=81=EF=BC=9B=202?= =?UTF-8?q?=E3=80=81=E4=BF=AE=E6=AD=A3decimal(5,=202)=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=AD=E6=8B=AC=E5=8F=B7=E5=86=85=E5=87=BA=E7=8E=B0=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC=E5=AF=BC=E8=87=B4=E8=A7=A3=E6=9E=90=E5=87=BA=E9=94=99?= =?UTF-8?q?=E7=9A=84bug=EF=BC=9B=203=E3=80=81=E4=BF=AE=E6=AD=A3xorm?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=B7=A5=E5=85=B7=E5=9C=A8windows=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E4=B8=8B=EF=BC=8C=E6=8C=87=E5=AE=9A=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=97=B6model=E5=90=8D=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84bug=20=E4=BA=8C=E3=80=81xor?= =?UTF-8?q?m=E5=AF=B9=E4=BA=8E=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=BA=E6=96=87=E6=9C=AC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=E4=B8=BA=E7=A9=BA=E7=99=BD=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=9A=84struct=E4=B8=ADdefault=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=E7=9A=84bug=EF=BC=8C=E5=B7=B2=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 商讯在线 --- engine.go | 37 ++-- mssql.go | 32 +-- mysql.go | 7 + oracle.go | 7 + postgres.go | 7 + table.go | 1 + xorm/go.go | 2 +- xorm/reverse.go | 419 ++++++++++++++++++----------------- xorm/templates/goxorm/config | 1 + 9 files changed, 278 insertions(+), 235 deletions(-) diff --git a/engine.go b/engine.go index e0aa2bf2..71ef63b4 100644 --- a/engine.go +++ b/engine.go @@ -484,8 +484,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j,ln := 0,len(tags); j < ln; j++ { - key := tags[j] + for j, key := range tags { k := strings.ToUpper(key) switch { case k == "<-": @@ -536,18 +535,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { - //[SWH|+] - if strings.HasSuffix(k, ",") { - j++ - for j < ln { - k += tags[j] - if strings.HasSuffix(tags[j], ")") { - break - } - j++ - } - } + } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k @@ -623,9 +611,24 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } } else { sqlType := Type2SQLType(fieldType) - col = &Column{engine.columnMapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType, - sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false, - TWOSIDES, false, false, false, false} + col = &Column{ + Name: engine.columnMapper.Obj2Table(t.Field(i).Name), + FieldName: t.Field(i).Name, + SQLType: sqlType, + Length: sqlType.DefaultLength, + Length2: sqlType.DefaultLength2, + Nullable: true, + Default: "", + Indexes: make(map[string]bool), + IsPrimaryKey: false, + IsAutoIncrement:false, + MapType: TWOSIDES, + IsCreated: false, + IsUpdated: false, + IsCascade: false, + IsVersion: false, + DefaultIsEmpty: false, + } } if col.IsAutoIncrement { col.Nullable = false diff --git a/mssql.go b/mssql.go index 3606332f..6e9776d2 100644 --- a/mssql.go +++ b/mssql.go @@ -136,8 +136,8 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { func (db *mssql) GetColumns(tableName string) ([]string, map[string]*Column, error) { args := []interface{}{} - s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale -from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id + s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale +from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id where a.object_id=object_id('` + tableName + `')` cnn, err := sql.Open(db.driverName, db.dataSourceName) if err != nil { @@ -187,6 +187,10 @@ where a.object_id=object_id('` + tableName + `')` if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col @@ -224,18 +228,18 @@ func (db *mssql) GetTables() ([]*Table, error) { func (db *mssql) GetIndexes(tableName string) (map[string]*Index, error) { args := []interface{}{tableName} - s := `SELECT -IXS.NAME AS [INDEX_NAME], -C.NAME AS [COLUMN_NAME], -IXS.is_unique AS [IS_UNIQUE], -CASE IXCS.IS_INCLUDED_COLUMN -WHEN 0 THEN 'NONE' -ELSE 'INCLUDED' END AS [IS_INCLUDED_COLUMN] -FROM SYS.INDEXES IXS -INNER JOIN SYS.INDEX_COLUMNS IXCS -ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID -INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID -AND IXCS.COLUMN_ID=C.COLUMN_ID + s := `SELECT +IXS.NAME AS [INDEX_NAME], +C.NAME AS [COLUMN_NAME], +IXS.is_unique AS [IS_UNIQUE], +CASE IXCS.IS_INCLUDED_COLUMN +WHEN 0 THEN 'NONE' +ELSE 'INCLUDED' END AS [IS_INCLUDED_COLUMN] +FROM SYS.INDEXES IXS +INNER JOIN SYS.INDEX_COLUMNS IXCS +ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID +INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID +AND IXCS.COLUMN_ID=C.COLUMN_ID WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? ` cnn, err := sql.Open(db.driverName, db.dataSourceName) diff --git a/mysql.go b/mysql.go index 4dcde839..aff13333 100644 --- a/mysql.go +++ b/mysql.go @@ -212,6 +212,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err case "COLUMN_DEFAULT": // add '' col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } case "COLUMN_TYPE": cts := strings.Split(string(content), "(") var len1, len2 int @@ -256,6 +259,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/oracle.go b/oracle.go index 4e3c6fb6..0b4238ca 100644 --- a/oracle.go +++ b/oracle.go @@ -139,6 +139,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er col.Name = strings.Trim(string(content), `" `) case "data_default": col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } case "nullable": if string(content) == "Y" { col.Nullable = true @@ -171,6 +174,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/postgres.go b/postgres.go index 97550543..4c7f97e2 100644 --- a/postgres.go +++ b/postgres.go @@ -177,6 +177,9 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, col.IsPrimaryKey = true } else { col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } } case "is_nullable": if string(content) == "YES" { @@ -218,6 +221,10 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/table.go b/table.go index 76b4c3ae..34cb0862 100644 --- a/table.go +++ b/table.go @@ -275,6 +275,7 @@ type Column struct { IsUpdated bool IsCascade bool IsVersion bool + DefaultIsEmpty bool } // generate column description string according dialect diff --git a/xorm/go.go b/xorm/go.go index 682f6b0b..533ce026 100644 --- a/xorm/go.go +++ b/xorm/go.go @@ -241,7 +241,7 @@ func tag(table *xorm.Table, col *xorm.Column) string { nstr := col.SQLType.Name if col.Length != 0 { if col.Length2 != 0 { - nstr += fmt.Sprintf("(%v, %v)", col.Length, col.Length2) + nstr += fmt.Sprintf("(%v,%v)", col.Length, col.Length2) } else { nstr += fmt.Sprintf("(%v)", col.Length) } diff --git a/xorm/reverse.go b/xorm/reverse.go index 17accfe5..7eab1980 100644 --- a/xorm/reverse.go +++ b/xorm/reverse.go @@ -1,26 +1,27 @@ package main import ( - "bytes" - "fmt" - _ "github.com/bylevel/pq" - "github.com/dvirsky/go-pylog/logging" - _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" - _ "github.com/mattn/go-sqlite3" - _ "github.com/ziutek/mymysql/godrv" - "io/ioutil" - "os" - "path" - "path/filepath" - "strconv" - "text/template" + "bytes" + "fmt" + _ "github.com/bylevel/pq" + "github.com/dvirsky/go-pylog/logging" + _ "github.com/go-sql-driver/mysql" + "github.com/lunny/xorm" + _ "github.com/mattn/go-sqlite3" + _ "github.com/ziutek/mymysql/godrv" + "io/ioutil" + "os" + "path" + "path/filepath" + "strconv" + "strings" //[SWH|+] + "text/template" ) var CmdReverse = &Command{ - UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]", - Short: "reverse a db to codes", - Long: ` + UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]", + Short: "reverse a db to codes", + Long: ` according database's tables and columns to generate codes for Go, C++ and etc. -m Generated one go file for every table @@ -33,236 +34,248 @@ according database's tables and columns to generate codes for Go, C++ and etc. } func init() { - CmdReverse.Run = runReverse - CmdReverse.Flags = map[string]bool{ - "-s": false, - "-l": false, - } + CmdReverse.Run = runReverse + CmdReverse.Flags = map[string]bool{ + "-s": false, + "-l": false, + } } var ( - genJson bool = false + genJson bool = false ) func printReversePrompt(flag string) { } type Tmpl struct { - Tables []*xorm.Table - Imports map[string]string - Model string + Tables []*xorm.Table + Imports map[string]string + Model string } func dirExists(dir string) bool { - d, e := os.Stat(dir) - switch { - case e != nil: - return false - case !d.IsDir(): - return false - } + d, e := os.Stat(dir) + switch { + case e != nil: + return false + case !d.IsDir(): + return false + } - return true + return true } func runReverse(cmd *Command, args []string) { - num := checkFlags(cmd.Flags, args, printReversePrompt) - if num == -1 { - return - } - args = args[num:] + num := checkFlags(cmd.Flags, args, printReversePrompt) + if num == -1 { + return + } + args = args[num:] - if len(args) < 3 { - fmt.Println("params error, please see xorm help reverse") - return - } + if len(args) < 3 { + fmt.Println("params error, please see xorm help reverse") + return + } - var isMultiFile bool = true - if use, ok := cmd.Flags["-s"]; ok { - isMultiFile = !use - } + var isMultiFile bool = true + if use, ok := cmd.Flags["-s"]; ok { + isMultiFile = !use + } - curPath, err := os.Getwd() - if err != nil { - fmt.Println(curPath) - return - } + curPath, err := os.Getwd() + if err != nil { + fmt.Println(curPath) + return + } - var genDir string - var model string - if len(args) == 4 { + var genDir string + var model string + if len(args) == 4 { - genDir, err = filepath.Abs(args[3]) - if err != nil { - fmt.Println(err) - return - } - model = path.Base(genDir) - } else { - model = "model" - genDir = path.Join(curPath, model) - } + genDir, err = filepath.Abs(args[3]) + if err != nil { + fmt.Println(err) + return + } + //[SWH|+] 经测试,path.Base不能解析windows下的“\”,需要替换为“/” + genDir = strings.Replace(genDir, "\\", "/", -1) + model = path.Base(genDir) + } else { + model = "model" + genDir = path.Join(curPath, model) + } - dir, err := filepath.Abs(args[2]) - if err != nil { - logging.Error("%v", err) - return - } + dir, err := filepath.Abs(args[2]) + if err != nil { + logging.Error("%v", err) + return + } - if !dirExists(dir) { - logging.Error("Template %v path is not exist", dir) - return - } + if !dirExists(dir) { + logging.Error("Template %v path is not exist", dir) + return + } - var langTmpl LangTmpl - var ok bool - var lang string = "go" + var langTmpl LangTmpl + var ok bool + var lang string = "go" + var prefix string = "" //[SWH|+] + cfgPath := path.Join(dir, "config") + info, err := os.Stat(cfgPath) + var configs map[string]string + if err == nil && !info.IsDir() { + configs = loadConfig(cfgPath) + if l, ok := configs["lang"]; ok { + lang = l + } + if j, ok := configs["genJson"]; ok { + genJson, err = strconv.ParseBool(j) + } + //[SWH|+] + if j, ok := configs["prefix"]; ok { + prefix = j + } + } - cfgPath := path.Join(dir, "config") - info, err := os.Stat(cfgPath) - var configs map[string]string - if err == nil && !info.IsDir() { - configs = loadConfig(cfgPath) - if l, ok := configs["lang"]; ok { - lang = l - } - if j, ok := configs["genJson"]; ok { - genJson, err = strconv.ParseBool(j) - } - } + if langTmpl, ok = langTmpls[lang]; !ok { + fmt.Println("Unsupported programing language", lang) + return + } - if langTmpl, ok = langTmpls[lang]; !ok { - fmt.Println("Unsupported programing language", lang) - return - } + os.MkdirAll(genDir, os.ModePerm) - os.MkdirAll(genDir, os.ModePerm) + Orm, err := xorm.NewEngine(args[0], args[1]) + if err != nil { + logging.Error("%v", err) + return + } - Orm, err := xorm.NewEngine(args[0], args[1]) - if err != nil { - logging.Error("%v", err) - return - } + tables, err := Orm.DBMetas() + if err != nil { + logging.Error("%v", err) + return + } - tables, err := Orm.DBMetas() - if err != nil { - logging.Error("%v", err) - return - } + filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { + if info.IsDir() { + return nil + } - filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { - if info.IsDir() { - return nil - } + if info.Name() == "config" { + return nil + } - if info.Name() == "config" { - return nil - } + bs, err := ioutil.ReadFile(f) + if err != nil { + logging.Error("%v", err) + return err + } - bs, err := ioutil.ReadFile(f) - if err != nil { - logging.Error("%v", err) - return err - } + t := template.New(f) + t.Funcs(langTmpl.Funcs) - t := template.New(f) - t.Funcs(langTmpl.Funcs) + tmpl, err := t.Parse(string(bs)) + if err != nil { + logging.Error("%v", err) + return err + } - tmpl, err := t.Parse(string(bs)) - if err != nil { - logging.Error("%v", err) - return err - } + var w *os.File + fileName := info.Name() + newFileName := fileName[:len(fileName)-4] + ext := path.Ext(newFileName) - var w *os.File - fileName := info.Name() - newFileName := fileName[:len(fileName)-4] - ext := path.Ext(newFileName) + if !isMultiFile { + w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + logging.Error("%v", err) + return err + } - if !isMultiFile { - w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } + imports := langTmpl.GenImports(tables) + tbls := make([]*xorm.Table, 0) + for _, table := range tables { + //[SWH|+] + if prefix != "" { + table.Name = strings.TrimPrefix(table.Name, prefix) + } + tbls = append(tbls, table) + } - imports := langTmpl.GenImports(tables) + newbytes := bytes.NewBufferString("") - tbls := make([]*xorm.Table, 0) - for _, table := range tables { - tbls = append(tbls, table) - } + t := &Tmpl{Tables: tbls, Imports: imports, Model: model} + err = tmpl.Execute(newbytes, t) + if err != nil { + logging.Error("%v", err) + return err + } - newbytes := bytes.NewBufferString("") + tplcontent, err := ioutil.ReadAll(newbytes) + if err != nil { + logging.Error("%v", err) + return err + } + var source string + if langTmpl.Formater != nil { + source, err = langTmpl.Formater(string(tplcontent)) + if err != nil { + logging.Error("%v", err) + return err + } + } else { + source = string(tplcontent) + } - t := &Tmpl{Tables: tbls, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } + w.WriteString(source) + w.Close() + } else { + for _, table := range tables { + //[SWH|+] + if prefix != "" { + table.Name = strings.TrimPrefix(table.Name, prefix) + } + // imports + tbs := []*xorm.Table{table} + imports := langTmpl.GenImports(tbs) + w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + logging.Error("%v", err) + return err + } - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v", err) - return err - } - } else { - source = string(tplcontent) - } + newbytes := bytes.NewBufferString("") - w.WriteString(source) - w.Close() - } else { - for _, table := range tables { - // imports - tbs := []*xorm.Table{table} - imports := langTmpl.GenImports(tbs) + t := &Tmpl{Tables: tbs, Imports: imports, Model: model} + err = tmpl.Execute(newbytes, t) + if err != nil { + logging.Error("%v", err) + return err + } - w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } + tplcontent, err := ioutil.ReadAll(newbytes) + if err != nil { + logging.Error("%v", err) + return err + } + var source string + if langTmpl.Formater != nil { + source, err = langTmpl.Formater(string(tplcontent)) + if err != nil { + logging.Error("%v-%v", err, string(tplcontent)) + return err + } + } else { + source = string(tplcontent) + } - newbytes := bytes.NewBufferString("") + w.WriteString(source) + w.Close() + } + } - t := &Tmpl{Tables: tbs, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } - - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v-%v", err, string(tplcontent)) - return err - } - } else { - source = string(tplcontent) - } - - w.WriteString(source) - w.Close() - } - } - - return nil - }) + return nil + }) } diff --git a/xorm/templates/goxorm/config b/xorm/templates/goxorm/config index e99ad029..5d7bf321 100644 --- a/xorm/templates/goxorm/config +++ b/xorm/templates/goxorm/config @@ -1,2 +1,3 @@ lang=go genJson=0 +prefix=cos_ From 781062130a8be265b2bf96e3d83659f90e826da0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 10 Feb 2014 11:26:08 +0800 Subject: [PATCH 13/41] add cachemapper --- mapper.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/mapper.go b/mapper.go index 2e9c220a..358d222f 100644 --- a/mapper.go +++ b/mapper.go @@ -2,6 +2,7 @@ package xorm import ( "strings" + "sync" ) // name translation between struct, fields names and table, column names @@ -10,6 +11,50 @@ type IMapper interface { Table2Obj(string) string } +type CacheMapper struct { + oriMapper IMapper + obj2tableCache map[string]string + obj2tableMutex sync.RWMutex + table2objCache map[string]string + table2objMutex sync.RWMutex +} + +func NewCacheMapper(mapper IMapper) *CacheMapper { + return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string), + table2objCache: make(map[string]string), + } +} + +func (m *CacheMapper) Obj2Table(o string) string { + m.obj2tableMutex.RLock() + t, ok := m.obj2tableCache[o] + m.obj2tableMutex.RUnlock() + if ok { + return t + } + + t = m.oriMapper.Obj2Table(o) + m.obj2tableMutex.Lock() + m.obj2tableCache[o] = t + m.obj2tableMutex.Unlock() + return t +} + +func (m *CacheMapper) Table2Obj(t string) string { + m.table2objMutex.RLock() + o, ok := m.table2objCache[t] + m.table2objMutex.RUnlock() + if ok { + return o + } + + o = m.oriMapper.Table2Obj(t) + m.table2objMutex.Lock() + m.table2objCache[t] = o + m.table2objMutex.Unlock() + return o +} + // SameMapper implements IMapper and provides same name between struct and // database table type SameMapper struct { From da96e0cc86fa239083abea3394a3708949e17405 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 10 Feb 2014 13:56:29 +0800 Subject: [PATCH 14/41] a little perfomance improved --- engine.go | 42 ++++++++++++++++++++++-------------------- xorm.go | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/engine.go b/engine.go index 714692e5..73adc8df 100644 --- a/engine.go +++ b/engine.go @@ -58,7 +58,7 @@ type Engine struct { DataSourceName string dialect dialect Tables map[reflect.Type]*Table - mutex *sync.Mutex + mutex *sync.RWMutex ShowSQL bool ShowErr bool ShowDebug bool @@ -421,12 +421,14 @@ func (engine *Engine) Having(conditions string) *Session { } func (engine *Engine) autoMapType(t reflect.Type) *Table { - engine.mutex.Lock() - defer engine.mutex.Unlock() + engine.mutex.RLock() table, ok := engine.Tables[t] + engine.mutex.RUnlock() if !ok { table = engine.mapType(t) + engine.mutex.Lock() engine.Tables[t] = table + engine.mutex.Unlock() } return table } @@ -484,7 +486,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j,ln := 0,len(tags); j < ln; j++ { + for j, ln := 0, len(tags); j < ln; j++ { key := tags[j] k := strings.ToUpper(key) switch { @@ -624,22 +626,22 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } else { sqlType := Type2SQLType(fieldType) col = &Column{ - Name: engine.columnMapper.Obj2Table(t.Field(i).Name), - FieldName: t.Field(i).Name, - SQLType: sqlType, - Length: sqlType.DefaultLength, - Length2: sqlType.DefaultLength2, - Nullable: true, - Default: "", - Indexes: make(map[string]bool), - IsPrimaryKey: false, - IsAutoIncrement:false, - MapType: TWOSIDES, - IsCreated: false, - IsUpdated: false, - IsCascade: false, - IsVersion: false, - DefaultIsEmpty: false, + Name: engine.columnMapper.Obj2Table(t.Field(i).Name), + FieldName: t.Field(i).Name, + SQLType: sqlType, + Length: sqlType.DefaultLength, + Length2: sqlType.DefaultLength2, + Nullable: true, + Default: "", + Indexes: make(map[string]bool), + IsPrimaryKey: false, + IsAutoIncrement: false, + MapType: TWOSIDES, + IsCreated: false, + IsUpdated: false, + IsCascade: false, + IsVersion: false, + DefaultIsEmpty: false, } } if col.IsAutoIncrement { diff --git a/xorm.go b/xorm.go index bff3f1bc..0a18d5e3 100644 --- a/xorm.go +++ b/xorm.go @@ -49,7 +49,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { } engine.Tables = make(map[reflect.Type]*Table) - engine.mutex = &sync.Mutex{} + engine.mutex = &sync.RWMutex{} engine.TagIdentifier = "xorm" engine.Filters = append(engine.Filters, &IdFilter{}) From d0567a63b49ef16462c99228a953b66d9400c9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=95=86=E8=AE=AF=E5=9C=A8=E7=BA=BF?= Date: Tue, 11 Feb 2014 21:42:14 +0800 Subject: [PATCH 15/41] =?UTF-8?q?=E8=A1=A5=E9=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 商讯在线 --- engine.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/engine.go b/engine.go index 73adc8df..6e2cbad5 100644 --- a/engine.go +++ b/engine.go @@ -486,8 +486,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j, ln := 0, len(tags); j < ln; j++ { - key := tags[j] + for j, key := range tags { k := strings.ToUpper(key) switch { case k == "<-": @@ -538,18 +537,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { - //[SWH|+] - if strings.HasSuffix(k, ",") { - j++ - for j < ln { - k += tags[j] - if strings.HasSuffix(tags[j], ")") { - break - } - j++ - } - } + } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k From 4f6106e168dfc6d3456d5541e7de1a4a017f848b Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Wed, 12 Feb 2014 01:35:26 +0800 Subject: [PATCH 16/41] private Engine.LogSQL and create ILogger interface that is compatible with log/syslog package. Also fixed use of LogError instead of LogSQL --- engine.go | 24 ++++++++++++++++-------- logger.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ rows.go | 13 ++++++------- session.go | 20 +++++++++----------- statement.go | 8 ++++---- xorm.go | 10 ++++++---- 6 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 logger.go diff --git a/engine.go b/engine.go index 2ac88f33..527e72c7 100644 --- a/engine.go +++ b/engine.go @@ -6,7 +6,6 @@ import ( "database/sql" "errors" "fmt" - "io" "os" "reflect" "strconv" @@ -34,7 +33,7 @@ type Engine struct { ShowWarn bool Pool IConnectPool Filters []core.Filter - Logger io.Writer + Logger ILogger // io.Writer Cacher core.Cacher tableCachers map[reflect.Type]core.Cacher } @@ -144,35 +143,44 @@ func (engine *Engine) Close() error { func (engine *Engine) Ping() error { session := engine.NewSession() defer session.Close() - engine.LogSQL("PING DATABASE", engine.DriverName) + engine.LogInfo("PING DATABASE", engine.DriverName) return session.Ping() } // logging sql -func (engine *Engine) LogSQL(contents ...interface{}) { +func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { if engine.ShowSQL { - io.WriteString(engine.Logger, fmt.Sprintln(contents...)) + if len(sqlArgs) > 0 { + engine.LogInfo("[sql]", sqlStr, "[args]", sqlArgs) + } else { + engine.LogInfo("[sql]", sqlStr) + } } } // logging error func (engine *Engine) LogError(contents ...interface{}) { if engine.ShowErr { - io.WriteString(engine.Logger, fmt.Sprintln(contents...)) + engine.Logger.Err(fmt.Sprintln(contents...)) } } +// logging error +func (engine *Engine) LogInfo(contents ...interface{}) { + engine.Logger.Info(fmt.Sprintln(contents...)) +} + // logging debug func (engine *Engine) LogDebug(contents ...interface{}) { if engine.ShowDebug { - io.WriteString(engine.Logger, fmt.Sprintln(contents...)) + engine.Logger.Debug(fmt.Sprintln(contents...)) } } // logging warn func (engine *Engine) LogWarn(contents ...interface{}) { if engine.ShowWarn { - io.WriteString(engine.Logger, fmt.Sprintln(contents...)) + engine.Logger.Warning(fmt.Sprintln(contents...)) } } diff --git a/logger.go b/logger.go new file mode 100644 index 00000000..c4c17bbb --- /dev/null +++ b/logger.go @@ -0,0 +1,48 @@ +package xorm + +import ( + "io" + "log" +) + +// logger interface, log/syslog conform with this interface +type ILogger interface { + Debug(m string) (err error) + Err(m string) (err error) + Info(m string) (err error) + Warning(m string) (err error) +} + +type SimpleLogger struct { + logger *log.Logger +} + +func NewSimpleLogger(out io.Writer) *SimpleLogger { + return &SimpleLogger{ + logger: log.New(out, "[xorm] ", log.Ldate|log.Lmicroseconds)} +} + +func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger { + return &SimpleLogger{ + logger: log.New(out, prefix, flag)} +} + +func (s *SimpleLogger) Debug(m string) (err error) { + s.logger.Println("[debug]", m) + return +} + +func (s *SimpleLogger) Err(m string) (err error) { + s.logger.Println("[error]", m) + return +} + +func (s *SimpleLogger) Info(m string) (err error) { + s.logger.Println("[info]", m) + return +} + +func (s *SimpleLogger) Warning(m string) (err error) { + s.logger.Println("[warning]", m) + return +} diff --git a/rows.go b/rows.go index ecbbce46..2d30e58e 100644 --- a/rows.go +++ b/rows.go @@ -32,24 +32,23 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { defer rows.session.Statement.Init() - var sql string + var sqlStr string var args []interface{} rows.session.Statement.RefTable = rows.session.Engine.autoMap(bean) if rows.session.Statement.RawSQL == "" { - sql, args = rows.session.Statement.genGetSql(bean) + sqlStr, args = rows.session.Statement.genGetSql(bean) } else { - sql = rows.session.Statement.RawSQL + sqlStr = rows.session.Statement.RawSQL args = rows.session.Statement.RawParams } for _, filter := range rows.session.Engine.Filters { - sql = filter.Do(sql, session.Engine.dialect, rows.session.Statement.RefTable) + sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable) } - rows.session.Engine.LogSQL(sql) - rows.session.Engine.LogSQL(args) + rows.session.Engine.logSQL(sqlStr, args) - rows.stmt, err = rows.session.Db.Prepare(sql) + rows.stmt, err = rows.session.Db.Prepare(sqlStr) if err != nil { rows.lastError = err defer rows.Close() diff --git a/session.go b/session.go index 271175fc..d19b10d9 100644 --- a/session.go +++ b/session.go @@ -282,7 +282,7 @@ func (session *Session) Begin() error { session.IsCommitedOrRollbacked = false session.Tx = tx - session.Engine.LogSQL("BEGIN TRANSACTION") + session.Engine.logSQL("BEGIN TRANSACTION") } return nil } @@ -290,7 +290,7 @@ func (session *Session) Begin() error { // When using transaction, you can rollback if any error func (session *Session) Rollback() error { if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { - session.Engine.LogSQL("ROLL BACK") + session.Engine.logSQL("ROLL BACK") session.IsCommitedOrRollbacked = true return session.Tx.Rollback() } @@ -300,7 +300,7 @@ func (session *Session) Rollback() error { // When using transaction, Commit will commit all operations. func (session *Session) Commit() error { if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { - session.Engine.LogSQL("COMMIT") + session.Engine.logSQL("COMMIT") session.IsCommitedOrRollbacked = true var err error if err = session.Tx.Commit(); err == nil { @@ -419,8 +419,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) } - session.Engine.LogSQL(sqlStr) - session.Engine.LogSQL(args) + session.Engine.logSQL(sqlStr, args) if session.IsAutoCommit { return session.innerExec(sqlStr, args...) @@ -1480,7 +1479,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i x := reflect.New(fieldType) err := json.Unmarshal([]byte(vv.String()), x.Interface()) if err != nil { - session.Engine.LogSQL(err) + session.Engine.LogError(err) return err } fieldValue.Set(x.Elem()) @@ -1700,8 +1699,7 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) *sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable) } - session.Engine.LogSQL(*sqlStr) - session.Engine.LogSQL(paramStr) + session.Engine.logSQL(*sqlStr, paramStr) } func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { @@ -2467,7 +2465,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val case reflect.Complex64, reflect.Complex128: bytes, err := json.Marshal(fieldValue.Interface()) if err != nil { - session.Engine.LogSQL(err) + session.Engine.LogError(err) return 0, err } return string(bytes), nil @@ -2479,7 +2477,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val if col.SQLType.IsText() { bytes, err := json.Marshal(fieldValue.Interface()) if err != nil { - session.Engine.LogSQL(err) + session.Engine.LogError(err) return 0, err } return string(bytes), nil @@ -2492,7 +2490,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val } else { bytes, err = json.Marshal(fieldValue.Interface()) if err != nil { - session.Engine.LogSQL(err) + session.Engine.LogError(err) return 0, err } } diff --git a/statement.go b/statement.go index 23cb0591..94e2baa4 100644 --- a/statement.go +++ b/statement.go @@ -210,7 +210,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { if col.SQLType.IsText() { bytes, err := json.Marshal(fieldValue.Interface()) if err != nil { - engine.LogSQL(err) + engine.LogError(err) continue } val = string(bytes) @@ -227,7 +227,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { } else { bytes, err = json.Marshal(fieldValue.Interface()) if err != nil { - engine.LogSQL(err) + engine.LogError(err) continue } val = bytes @@ -373,7 +373,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{}, if col.SQLType.IsText() { bytes, err := json.Marshal(fieldValue.Interface()) if err != nil { - engine.LogSQL(err) + engine.LogError(err) continue } val = string(bytes) @@ -390,7 +390,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{}, } else { bytes, err = json.Marshal(fieldValue.Interface()) if err != nil { - engine.LogSQL(err) + engine.LogError(err) continue } val = bytes diff --git a/xorm.go b/xorm.go index 40653eea..497cd005 100644 --- a/xorm.go +++ b/xorm.go @@ -46,9 +46,11 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { return nil, err } - engine := &Engine{DriverName: driverName, - DataSourceName: dataSourceName, dialect: dialect, - tableCachers: make(map[reflect.Type]core.Cacher)} + engine := &Engine{ + DriverName: driverName, + DataSourceName: dataSourceName, + dialect: dialect, + tableCachers: make(map[reflect.Type]core.Cacher)} engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper))) @@ -58,7 +60,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { engine.mutex = &sync.RWMutex{} engine.TagIdentifier = "xorm" - engine.Logger = os.Stdout + engine.Logger = NewSimpleLogger(os.Stdout) //engine.Pool = NewSimpleConnectPool() //engine.Pool = NewNoneConnectPool() From 1927a64cf31f64a9672f070be1c012b562640c89 Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Wed, 12 Feb 2014 11:29:27 +0800 Subject: [PATCH 17/41] Update CONTRIBUTING.md add links for fork a repo to --- CONTRIBUTING.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7fde071..6f65c2ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,17 @@ ## Contributing to xorm -`xorm` has a backlog of pull requests, but contributions are still very +`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very much welcome. You can help with patch review, submitting bug reports, or adding new functionality. There is no formal style guide, but please conform to the style of existing code and general Go formatting conventions when submitting patches. +* [fork a repo](https://help.github.com/articles/fork-a-repo) +* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request) + ### Patch review -Help review existing open pull requests by commenting on the code or +Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or proposed functionality. ### Bug reports From f76bd3b102c97d25ec7ad242d4367e5f603ee792 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 12 Feb 2014 15:10:37 +0800 Subject: [PATCH 18/41] add gobuild as cases --- README.md | 2 ++ README_CN.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 85e5d46c..c5fb4ca7 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ Or * [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) +* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) + * [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) * [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) diff --git a/README_CN.md b/README_CN.md index 8088f423..d7e8de80 100644 --- a/README_CN.md +++ b/README_CN.md @@ -81,6 +81,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 * [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) +* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) + * [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) * [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) From 146d5db5eae5fb854e607591d4aa0cc66b0cc4c4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 18 Feb 2014 14:10:51 +0800 Subject: [PATCH 19/41] bug fixed --- mysql.go | 3 ++- session.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql.go b/mysql.go index aff13333..23b53641 100644 --- a/mysql.go +++ b/mysql.go @@ -111,6 +111,7 @@ func (db *mysql) SqlType(c *Column) string { switch t := c.SQLType.Name; t { case Bool: res = TinyInt + c.Length = 1 case Serial: c.IsAutoIncrement = true c.IsPrimaryKey = true @@ -259,7 +260,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" - }else{ + } else { if col.DefaultIsEmpty { col.Default = "''" } diff --git a/session.go b/session.go index 75570fcd..825acc46 100644 --- a/session.go +++ b/session.go @@ -2627,7 +2627,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { // Method InsertOne insert only one struct into database as a record. // The in parameter bean must a struct or a point to struct. The return -// parameter is lastInsertId and error +// parameter is inserted and error func (session *Session) InsertOne(bean interface{}) (int64, error) { err := session.newDb() if err != nil { From 45b3f9775eff90e984129cb08e77b0b7f883ef0f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 25 Feb 2014 18:45:24 +0800 Subject: [PATCH 20/41] bug fixed for statement.IdParam --- statement.go | 1 + 1 file changed, 1 insertion(+) diff --git a/statement.go b/statement.go index b36a2ebf..4bde5c7b 100644 --- a/statement.go +++ b/statement.go @@ -61,6 +61,7 @@ func (statement *Statement) Init() { statement.columnMap = make(map[string]bool) statement.ConditionStr = "" statement.AltTableName = "" + statement.IdParam = nil statement.RawSQL = "" statement.RawParams = make([]interface{}, 0) statement.BeanArgs = make([]interface{}, 0) From df3bda568b07bcf4b64806c2bb96a5bfe20bd5c2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 12 Mar 2014 23:23:01 +0800 Subject: [PATCH 21/41] improved QuickStart.md --- docs/QuickStart.md | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 6fc55f7b..dc2f0cd3 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -3,7 +3,7 @@ xorm 快速入门 * [1.创建Orm引擎](#10) * [2.定义表结构体](#20) - * [2.1.名称映射规则](#21) + * [2.1.名称映射规则](#21) * [2.2.前缀映射规则和后缀映射规则](#22) * [2.3.使用Table和Tag改变名称映射](#23) * [2.4.Column属性定义](#24) @@ -20,7 +20,7 @@ xorm 快速入门 * [5.3.Get方法](#63) * [5.4.Find方法](#64) * [5.5.Iterate方法](#65) - * [5.6.Count方法](#66) + * [5.6.Count方法](#66) * [5.7.Rows方法](#67) * [6.更新数据](#70) * [6.1.乐观锁](#71) @@ -45,7 +45,7 @@ xorm 快速入门 import ( _ "github.com/go-sql-driver/mysql" "github.com/lunny/xorm" -) +) engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8") defer engine.Close() ``` @@ -58,20 +58,20 @@ import ( "github.com/lunny/xorm" ) engine, err = xorm.NewEngine("sqlite3", "./test.db") -defer engine.Close() +defer engine.Close() ``` 一般如果只针对一个数据库进行操作,只需要创建一个Engine即可。Engine支持在多GoRutine下使用。 xorm当前支持五种驱动四个数据库如下: -* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) - +* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) + * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) * SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) -* Postgres: [github.com/lib/pq](https://github.com/lib/pq) +* Postgres: [github.com/lib/pq](https://github.com/lib/pq) * MsSql: [github.com/lunny/godbc](https://githubcom/lunny/godbc) @@ -120,9 +120,9 @@ engine.SetMapper(SameMapper{}) 同时需要注意的是: -* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 +* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 * 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: - + ```Go engine.SetTableMapper(SameMapper{}) engine.SetColumnMapper(SnakeMapper{}) @@ -356,7 +356,7 @@ affected, err := engine.Insert(user, &questions) ``` 这里需要注意以下几点: -* 这里虽然支持同时插入,但这些插入并没有事务关系。因此有可能在中间插入出错后,后面的插入将不会继续。 +* 这里虽然支持同时插入,但这些插入并没有事务关系。因此有可能在中间插入出错后,后面的插入将不会继续。 * 多条插入会自动生成`Insert into table values (),(),()`的语句,因此这样的语句有一个最大的记录数,根据经验测算在150条左右。大于150条后,生成的sql语句将太长可能导致执行失败。因此在插入大量数据时,目前需要自行分割成每150条插入一次。 @@ -504,7 +504,7 @@ has, err := engine.Get(user) 1) 传入Slice用于返回数据 ```Go -everyone := make([]Userinfo, 0) +everyone := make([]Userinfo, 0) err := engine.Find(&everyone) pEveryOne := make([]*Userinfo, 0) @@ -643,7 +643,7 @@ results, err := engine.Query(sql) ```Go sql = "update `userinfo` set username=? where id=?" -res, err := engine.Exec(sql, "xiaolun", 1) +res, err := engine.Exec(sql, "xiaolun", 1) ``` @@ -678,9 +678,11 @@ if err != nil { err = session.Commit() if err != nil { return -} +} ``` +* 注意如果您使用的是mysql,数据库引擎为innodb事务才有效,myisam引擎是不支持事务的。 + ## 11.缓存 @@ -715,7 +717,7 @@ engine.MapCacher(&user, nil) 1. 当使用了`Distinct`,`Having`,`GroupBy`方法将不会使用缓存 2. 在`Get`或者`Find`时使用了`Cols`,`Omit`方法,则在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。 - + 3. 在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。比如: ```Go @@ -752,14 +754,14 @@ xorm工具提供了xorm命令,能够帮助做很多事情。 ## 15.那些年我们踩过的坑 -* 怎么同时使用xorm的tag和json的tag? - -答:使用空格 - -```Go -type User struct { - Name string `json:"name" xorm:"name"` -} +* 怎么同时使用xorm的tag和json的tag? + +答:使用空格 + +```Go +type User struct { + Name string `json:"name" xorm:"name"` +} ``` * 我的struct里面包含bool类型,为什么它不能作为条件也没法用Update更新? From 1c81f5257604dcc768e3e33480ad358acbb8f14f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 14 Mar 2014 15:05:58 +0800 Subject: [PATCH 22/41] update tests --- base_test.go | 30 +++++++++++++++++++----------- xorm/reverse.go | 13 +++++++------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/base_test.go b/base_test.go index 91da58c6..92eb6290 100644 --- a/base_test.go +++ b/base_test.go @@ -331,37 +331,45 @@ func update(engine *Engine, t *testing.T) { panic(err) } - cnt, err = engine.Insert(&Article{0, "1", "2", "3", "4", "5", 2}) + defer func() { + err = engine.DropTables(&Article{}) + if err != nil { + t.Error(err) + panic(err) + } + }() + + a := &Article{0, "1", "2", "3", "4", "5", 2} + cnt, err = engine.Insert(a) if err != nil { t.Error(err) panic(err) } if cnt != 1 { - err = errors.New("insert not returned 1") + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) t.Error(err) panic(err) - return } - cnt, err = engine.Id(1).Update(&Article{Name: "6"}) + if a.Id == 0 { + err = errors.New("insert returned id is 0") + t.Error(err) + panic(err) + } + + cnt, err = engine.Id(a.Id).Update(&Article{Name: "6"}) if err != nil { t.Error(err) panic(err) } if cnt != 1 { - err = errors.New("update not returned 1") + err = errors.New(fmt.Sprintf("insert not returned 1 but %d", cnt)) t.Error(err) panic(err) return } - - err = engine.DropTables(&Article{}) - if err != nil { - t.Error(err) - panic(err) - } } func updateSameMapper(engine *Engine, t *testing.T) { diff --git a/xorm/reverse.go b/xorm/reverse.go index 7eab1980..e0a0f3b3 100644 --- a/xorm/reverse.go +++ b/xorm/reverse.go @@ -3,12 +3,6 @@ package main import ( "bytes" "fmt" - _ "github.com/bylevel/pq" - "github.com/dvirsky/go-pylog/logging" - _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" - _ "github.com/mattn/go-sqlite3" - _ "github.com/ziutek/mymysql/godrv" "io/ioutil" "os" "path" @@ -16,6 +10,13 @@ import ( "strconv" "strings" //[SWH|+] "text/template" + + "github.com/dvirsky/go-pylog/logging" + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" + "github.com/lunny/xorm" + _ "github.com/mattn/go-sqlite3" + _ "github.com/ziutek/mymysql/godrv" ) var CmdReverse = &Command{ From d97ff5ee86a0bc7d2f75e850bb7acec785303b6e Mon Sep 17 00:00:00 2001 From: xiaoxiao Date: Wed, 19 Mar 2014 16:55:50 +0800 Subject: [PATCH 23/41] Init commit --- .gitignore | 22 ++++++++++++++++++++++ LICENSE | 27 +++++++++++++++++++++++++++ README.md | 4 ++++ 3 files changed, 53 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6cd1df2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3af16b07 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..523200ea --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +xorm +==== + +xorm \ No newline at end of file From 11aa2a973cba567f294c4516c30cc5852c9e3ff9 Mon Sep 17 00:00:00 2001 From: lunny Date: Thu, 20 Mar 2014 13:46:32 +0000 Subject: [PATCH 24/41] Init commit --- .gitignore | 22 ++++++++++++++++++++++ LICENSE | 27 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6cd1df2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3af16b07 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file From 8d5bd092d8d2f471daeff3f22cc39c210feb9851 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 23 Mar 2014 17:16:11 +0800 Subject: [PATCH 25/41] license --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 3af16b07..9ac0c261 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014 +Copyright (c) 2013 - 2014 All rights reserved. Redistribution and use in source and binary forms, with or without @@ -24,4 +24,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 3aed2090a024c88472e7d5f5db97c38adfa564ea Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 24 Mar 2014 20:41:07 +0800 Subject: [PATCH 26/41] add AllCols for update all cols --- base_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ session.go | 17 +++++++++++++---- statement.go | 16 ++++++++++++---- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/base_test.go b/base_test.go index 92eb6290..53d15bfc 100644 --- a/base_test.go +++ b/base_test.go @@ -370,6 +370,53 @@ func update(engine *Engine, t *testing.T) { panic(err) return } + + type UpdateAllCols struct { + Id int64 + Bool bool + String string + } + + col1 := &UpdateAllCols{} + err = engine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = engine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateAllCols{col1.Id, true, ""} + _, err = engine.Id(col2.Id).AllCols().Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateAllCols{} + has, err := engine.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 + } } func updateSameMapper(engine *Engine, t *testing.T) { diff --git a/session.go b/session.go index 825acc46..731027ce 100644 --- a/session.go +++ b/session.go @@ -126,6 +126,11 @@ func (session *Session) Cols(columns ...string) *Session { return session } +func (session *Session) AllCols() *Session { + session.Statement.AllCols() + return session +} + func (session *Session) NoCascade() *Session { session.Statement.UseCascade = false return session @@ -1023,7 +1028,8 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) if len(condiBean) > 0 { colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true, - false, true, session.Statement.allUseBool, session.Statement.boolColumnMap) + false, true, session.Statement.allUseBool, session.Statement.useAllCols, + session.Statement.boolColumnMap) session.Statement.ConditionStr = strings.Join(colNames, " AND ") session.Statement.BeanArgs = args } @@ -2838,7 +2844,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 if session.Statement.ColumnStr == "" { colNames, args = buildConditions(session.Engine, table, bean, false, false, - false, false, session.Statement.allUseBool, session.Statement.boolColumnMap) + false, false, session.Statement.allUseBool, session.Statement.useAllCols, + session.Statement.boolColumnMap) } else { colNames, args, err = table.genCols(session, bean, true, true) if err != nil { @@ -2872,7 +2879,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 if len(condiBean) > 0 { condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true, - false, true, session.Statement.allUseBool, session.Statement.boolColumnMap) + false, true, session.Statement.allUseBool, session.Statement.useAllCols, + session.Statement.boolColumnMap) } var condition = "" @@ -3060,7 +3068,8 @@ func (session *Session) Delete(bean interface{}) (int64, error) { table := session.Engine.autoMap(bean) session.Statement.RefTable = table colNames, args := buildConditions(session.Engine, table, bean, true, true, - false, true, session.Statement.allUseBool, session.Statement.boolColumnMap) + false, true, session.Statement.allUseBool, session.Statement.useAllCols, + session.Statement.boolColumnMap) var condition = "" diff --git a/statement.go b/statement.go index 4bde5c7b..80c5dccb 100644 --- a/statement.go +++ b/statement.go @@ -25,6 +25,7 @@ type Statement struct { HavingStr string ColumnStr string columnMap map[string]bool + useAllCols bool OmitStr string ConditionStr string AltTableName string @@ -239,7 +240,8 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { // Auto generating conditions according a struct func buildConditions(engine *Engine, table *Table, bean interface{}, - includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, allUseBool bool, + includeVersion bool, includeUpdated bool, includeNil bool, + includeAutoIncr bool, allUseBool bool, useAllCols bool, boolColumnMap map[string]bool) ([]string, []interface{}) { colNames := make([]string, 0) @@ -262,7 +264,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, fieldValue := col.ValueOf(bean) fieldType := reflect.TypeOf(fieldValue.Interface()) - requiredField := false + requiredField := useAllCols if fieldType.Kind() == reflect.Ptr { if fieldValue.IsNil() { if includeNil { @@ -517,6 +519,11 @@ func (statement *Statement) Cols(columns ...string) *Statement { return statement } +func (statement *Statement) AllCols() *Statement { + statement.useAllCols = true + return statement +} + // indicates that use bool fields as update contents and query contiditions func (statement *Statement) UseBool(columns ...string) *Statement { if len(columns) > 0 { @@ -719,7 +726,8 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, true, - false, true, statement.allUseBool, statement.boolColumnMap) + false, true, statement.allUseBool, statement.useAllCols, + statement.boolColumnMap) statement.ConditionStr = strings.Join(colNames, " AND ") statement.BeanArgs = args @@ -758,7 +766,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{} statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, true, false, - true, statement.allUseBool, statement.boolColumnMap) + true, statement.allUseBool, statement.useAllCols,statement.boolColumnMap) statement.ConditionStr = strings.Join(colNames, " AND ") statement.BeanArgs = args From 182428e13db4959977eb01db61e17eba560b2bd4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 27 Mar 2014 22:16:06 +0800 Subject: [PATCH 27/41] add use case gogs --- README.md | 8 +++----- README_CN.md | 9 +++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1ed46fed..4f85368b 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ Or # Cases +* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) + * [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) * [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) @@ -86,11 +88,7 @@ Or * [Very Hour](http://veryhour.com/) -* [GoCMS](https://github.com/zzdboy/GoCMS) - -# Todo - -[Todo List](https://trello.com/b/IHsuAnhk/xorm) +* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) # Discuss diff --git a/README_CN.md b/README_CN.md index d7e8de80..35b7ed70 100644 --- a/README_CN.md +++ b/README_CN.md @@ -79,6 +79,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 ## 案例 +* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) + * [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) * [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) @@ -89,12 +91,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 * [Very Hour](http://veryhour.com/) -* [GoCMS](https://github.com/zzdboy/GoCMS) - - -## Todo - -[开发计划](https://trello.com/b/IHsuAnhk/xorm) +* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) ## 讨论 From ff3a06b3dc619d096025235a3e49af40e1bd4e6a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 28 Mar 2014 15:03:35 +0800 Subject: [PATCH 28/41] ql support --- engine.go | 1 + ql.go | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ql_test.go | 140 ++++++++++++++++++++++++++++++++ xorm.go | 4 + 4 files changed, 377 insertions(+) create mode 100644 ql.go create mode 100644 ql_test.go diff --git a/engine.go b/engine.go index 6e2cbad5..23038e1d 100644 --- a/engine.go +++ b/engine.go @@ -23,6 +23,7 @@ const ( MSSQL = "mssql" ORACLE_OCI = "oci8" + QL = "ql" ) // a dialect is a driver's wrapper diff --git a/ql.go b/ql.go new file mode 100644 index 00000000..8f26f3b5 --- /dev/null +++ b/ql.go @@ -0,0 +1,232 @@ +package xorm + +import ( + "database/sql" + "strings" +) + +type ql struct { + base +} + +type qlParser struct { +} + +func (p *qlParser) parse(driverName, dataSourceName string) (*uri, error) { + return &uri{dbType: QL, dbName: dataSourceName}, nil +} + +func (db *ql) Init(drivername, dataSourceName string) error { + return db.base.init(&qlParser{}, drivername, dataSourceName) +} + +func (db *ql) SqlType(c *Column) string { + switch t := c.SQLType.Name; t { + case Date, DateTime, TimeStamp, Time: + return Numeric + case TimeStampz: + return Text + case Char, Varchar, TinyText, Text, MediumText, LongText: + return Text + case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool: + return Integer + case Float, Double, Real: + return Real + case Decimal, Numeric: + return Numeric + case TinyBlob, Blob, MediumBlob, LongBlob, Bytea, Binary, VarBinary: + return Blob + case Serial, BigSerial: + c.IsPrimaryKey = true + c.IsAutoIncrement = true + c.Nullable = false + return Integer + default: + return t + } +} + +func (db *ql) SupportInsertMany() bool { + return true +} + +func (db *ql) QuoteStr() string { + return "" +} + +func (db *ql) AutoIncrStr() string { + return "AUTOINCREMENT" +} + +func (db *ql) SupportEngine() bool { + return false +} + +func (db *ql) SupportCharset() bool { + return false +} + +func (db *ql) IndexOnTable() bool { + return false +} + +func (db *ql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { + args := []interface{}{idxName} + return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args +} + +func (db *ql) TableCheckSql(tableName string) (string, []interface{}) { + args := []interface{}{tableName} + return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args +} + +func (db *ql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { + args := []interface{}{tableName} + sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))" + return sql, args +} + +func (db *ql) GetColumns(tableName string) ([]string, map[string]*Column, error) { + args := []interface{}{tableName} + s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" + cnn, err := sql.Open(db.driverName, db.dataSourceName) + if err != nil { + return nil, nil, err + } + defer cnn.Close() + res, err := query(cnn, s, args...) + if err != nil { + return nil, nil, err + } + + var sql string + for _, record := range res { + for name, content := range record { + if name == "sql" { + sql = string(content) + } + } + } + + nStart := strings.Index(sql, "(") + nEnd := strings.Index(sql, ")") + colCreates := strings.Split(sql[nStart+1:nEnd], ",") + cols := make(map[string]*Column) + colSeq := make([]string, 0) + for _, colStr := range colCreates { + fields := strings.Fields(strings.TrimSpace(colStr)) + col := new(Column) + col.Indexes = make(map[string]bool) + col.Nullable = true + for idx, field := range fields { + if idx == 0 { + col.Name = strings.Trim(field, "`[] ") + continue + } else if idx == 1 { + col.SQLType = SQLType{field, 0, 0} + } + switch field { + case "PRIMARY": + col.IsPrimaryKey = true + case "AUTOINCREMENT": + col.IsAutoIncrement = true + case "NULL": + if fields[idx-1] == "NOT" { + col.Nullable = false + } else { + col.Nullable = true + } + } + } + cols[col.Name] = col + colSeq = append(colSeq, col.Name) + } + return colSeq, cols, nil +} + +func (db *ql) GetTables() ([]*Table, error) { + args := []interface{}{} + s := "SELECT name FROM sqlite_master WHERE type='table'" + + cnn, err := sql.Open(db.driverName, db.dataSourceName) + if err != nil { + return nil, err + } + defer cnn.Close() + res, err := query(cnn, s, args...) + if err != nil { + return nil, err + } + + tables := make([]*Table, 0) + for _, record := range res { + table := new(Table) + for name, content := range record { + switch name { + case "name": + table.Name = string(content) + } + } + if table.Name == "sqlite_sequence" { + continue + } + tables = append(tables, table) + } + return tables, nil +} + +func (db *ql) GetIndexes(tableName string) (map[string]*Index, error) { + args := []interface{}{tableName} + s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?" + cnn, err := sql.Open(db.driverName, db.dataSourceName) + if err != nil { + return nil, err + } + defer cnn.Close() + res, err := query(cnn, s, args...) + if err != nil { + return nil, err + } + + indexes := make(map[string]*Index, 0) + for _, record := range res { + index := new(Index) + sql := string(record["sql"]) + + if sql == "" { + continue + } + + nNStart := strings.Index(sql, "INDEX") + nNEnd := strings.Index(sql, "ON") + if nNStart == -1 || nNEnd == -1 { + continue + } + + indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []") + //fmt.Println(indexName) + if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { + index.Name = indexName[5+len(tableName) : len(indexName)] + } else { + index.Name = indexName + } + + if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") { + index.Type = UniqueType + } else { + index.Type = IndexType + } + + nStart := strings.Index(sql, "(") + nEnd := strings.Index(sql, ")") + colIndexes := strings.Split(sql[nStart+1:nEnd], ",") + + index.Cols = make([]string, 0) + for _, col := range colIndexes { + index.Cols = append(index.Cols, strings.Trim(col, "` []")) + } + indexes[index.Name] = index + } + + return indexes, nil +} diff --git a/ql_test.go b/ql_test.go new file mode 100644 index 00000000..46d0104d --- /dev/null +++ b/ql_test.go @@ -0,0 +1,140 @@ +package xorm + +import ( + "database/sql" + "os" + "testing" + + _ "github.com/mattn/ql-driver" +) + +func newQlEngine() (*Engine, error) { + os.Remove("./ql.db") + return NewEngine("ql", "./ql.db") +} + +func newQlDriverDB() (*sql.DB, error) { + os.Remove("./ql.db") + return sql.Open("ql", "./ql.db") +} + +func TestQl(t *testing.T) { + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + engine.ShowSQL = showTestSql + engine.ShowErr = showTestSql + engine.ShowWarn = showTestSql + engine.ShowDebug = showTestSql + + testAll(engine, t) + testAll2(engine, t) + testAll3(engine, t) +} + +func TestQlWithCache(t *testing.T) { + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) + engine.ShowSQL = showTestSql + engine.ShowErr = showTestSql + engine.ShowWarn = showTestSql + engine.ShowDebug = showTestSql + + testAll(engine, t) + testAll2(engine, t) +} + +const ( + createTableQl = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, `title` TEXT NULL, `age` TEXT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL);" + dropTableQl = "DROP TABLE IF EXISTS `big_struct`;" +) + +func BenchmarkQlDriverInsert(t *testing.B) { + doBenchDriver(newQlDriverDB, createTableQl, dropTableQl, + doBenchDriverInsert, t) +} + +func BenchmarkQlDriverFind(t *testing.B) { + doBenchDriver(newQlDriverDB, createTableQl, dropTableQl, + doBenchDriverFind, t) +} + +func BenchmarkQlNoCacheInsert(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + //engine.ShowSQL = true + doBenchInsert(engine, t) +} + +func BenchmarkQlNoCacheFind(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + //engine.ShowSQL = true + doBenchFind(engine, t) +} + +func BenchmarkQlNoCacheFindPtr(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + //engine.ShowSQL = true + doBenchFindPtr(engine, t) +} + +func BenchmarkQlCacheInsert(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) + doBenchInsert(engine, t) +} + +func BenchmarkQlCacheFind(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) + doBenchFind(engine, t) +} + +func BenchmarkQlCacheFindPtr(t *testing.B) { + t.StopTimer() + engine, err := newQlEngine() + defer engine.Close() + if err != nil { + t.Error(err) + return + } + engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) + doBenchFindPtr(engine, t) +} diff --git a/xorm.go b/xorm.go index 0a18d5e3..a4bded59 100644 --- a/xorm.go +++ b/xorm.go @@ -40,6 +40,10 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { } else if driverName == ORACLE_OCI { engine.dialect = &oracle{} engine.Filters = append(engine.Filters, &QuoteFilter{}) + } else if driverName == QL { + engine.dialect = &ql{} + engine.Filters = append(engine.Filters, &PgSeqFilter{}) + engine.Filters = append(engine.Filters, &QuoteFilter{}) } else { return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName)) } From 9d64ef50133ec413bcd426f55c65d331c2af6f49 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 5 Apr 2014 22:14:00 +0800 Subject: [PATCH 29/41] bug fixed --- engine.go | 67 ++++++++------- mssql.go | 8 +- mysql.go | 8 ++ ql.go | 232 --------------------------------------------------- ql_test.go | 140 ------------------------------- session.go | 2 +- statement.go | 14 +--- 7 files changed, 53 insertions(+), 418 deletions(-) delete mode 100644 ql.go delete mode 100644 ql_test.go diff --git a/engine.go b/engine.go index 23038e1d..205ed873 100644 --- a/engine.go +++ b/engine.go @@ -34,6 +34,8 @@ type dialect interface { SqlType(t *Column) string SupportInsertMany() bool QuoteStr() string + RollBackStr() string + DropTableSql(tableName string) string AutoIncrStr() string SupportEngine() bool SupportCharset() bool @@ -449,6 +451,18 @@ func (engine *Engine) newTable() *Table { return table } +func addIndex(indexName string, table *Table, col *Column, indexType int) { + if index, ok := table.Indexes[indexName]; ok { + index.AddColumn(col.Name) + col.Indexes[index.Name] = true + } else { + index := NewIndex(indexName, indexType) + index.AddColumn(col.Name) + table.AddIndex(index) + col.Indexes[index.Name] = true + } +} + func (engine *Engine) mapType(t reflect.Type) *Table { table := engine.newTable() table.Name = engine.tableMapper.Obj2Table(t.Name()) @@ -484,8 +498,9 @@ func (engine *Engine) mapType(t reflect.Type) *Table { table.PrimaryKeys = parentTable.PrimaryKeys continue } - var indexType int - var indexName string + + indexNames := make(map[string]int) + var isIndex, isUnique bool var preKey string for j, key := range tags { k := strings.ToUpper(key) @@ -521,15 +536,15 @@ func (engine *Engine) mapType(t reflect.Type) *Table { case k == "UPDATED": col.IsUpdated = true case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"): - indexType = IndexType - indexName = k[len("INDEX")+1 : len(k)-1] + indexName := k[len("INDEX")+1 : len(k)-1] + indexNames[indexName] = IndexType case k == "INDEX": - indexType = IndexType + isIndex = true case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"): - indexName = k[len("UNIQUE")+1 : len(k)-1] - indexType = UniqueType + indexName := k[len("UNIQUE")+1 : len(k)-1] + indexNames[indexName] = UniqueType case k == "UNIQUE": - indexType = UniqueType + isUnique = true case k == "NOTNULL": col.Nullable = false case k == "NOT": @@ -584,32 +599,15 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if col.Name == "" { col.Name = engine.columnMapper.Obj2Table(t.Field(i).Name) } - if indexType == IndexType { - if indexName == "" { - indexName = col.Name - } - if index, ok := table.Indexes[indexName]; ok { - index.AddColumn(col.Name) - col.Indexes[index.Name] = true - } else { - index := NewIndex(indexName, IndexType) - index.AddColumn(col.Name) - table.AddIndex(index) - col.Indexes[index.Name] = true - } - } else if indexType == UniqueType { - if indexName == "" { - indexName = col.Name - } - if index, ok := table.Indexes[indexName]; ok { - index.AddColumn(col.Name) - col.Indexes[index.Name] = true - } else { - index := NewIndex(indexName, UniqueType) - index.AddColumn(col.Name) - table.AddIndex(index) - col.Indexes[index.Name] = true - } + + if isUnique { + indexNames[col.Name] = UniqueType + } else if isIndex { + indexNames[col.Name] = IndexType + } + + for indexName, indexType := range indexNames { + addIndex(indexName, table, col, indexType) } } } else { @@ -810,6 +808,7 @@ func (engine *Engine) Sync(beans ...interface{}) error { } } } else if index.Type == IndexType { + fmt.Println("index:", table.Name, name, index) isExist, err := session.isIndexExist2(table.Name, index.Cols, false) if err != nil { return err diff --git a/mssql.go b/mssql.go index 6e9776d2..54c93e71 100644 --- a/mssql.go +++ b/mssql.go @@ -108,6 +108,12 @@ func (db *mssql) AutoIncrStr() string { return "IDENTITY" } +func (db *mssql) DropTableSql(tableName string) string { + return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+ + "object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+ + "DROP TABLE \"%s\"", tableName, tableName) +} + func (db *mssql) SupportCharset() bool { return false } @@ -187,7 +193,7 @@ where a.object_id=object_id('` + tableName + `')` if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" - }else{ + } else { if col.DefaultIsEmpty { col.Default = "''" } diff --git a/mysql.go b/mysql.go index 23b53641..8d0cfaa3 100644 --- a/mysql.go +++ b/mysql.go @@ -89,6 +89,14 @@ func (b *base) DBType() string { return b.uri.dbType } +func (db *base) RollBackStr() string { + return "ROLL BACK" +} + +func (db *base) DropTableSql(tableName string) string { + return fmt.Sprintf("DROP TABLE IF EXISTS `%s`", tableName) +} + type mysql struct { base net string diff --git a/ql.go b/ql.go deleted file mode 100644 index 8f26f3b5..00000000 --- a/ql.go +++ /dev/null @@ -1,232 +0,0 @@ -package xorm - -import ( - "database/sql" - "strings" -) - -type ql struct { - base -} - -type qlParser struct { -} - -func (p *qlParser) parse(driverName, dataSourceName string) (*uri, error) { - return &uri{dbType: QL, dbName: dataSourceName}, nil -} - -func (db *ql) Init(drivername, dataSourceName string) error { - return db.base.init(&qlParser{}, drivername, dataSourceName) -} - -func (db *ql) SqlType(c *Column) string { - switch t := c.SQLType.Name; t { - case Date, DateTime, TimeStamp, Time: - return Numeric - case TimeStampz: - return Text - case Char, Varchar, TinyText, Text, MediumText, LongText: - return Text - case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool: - return Integer - case Float, Double, Real: - return Real - case Decimal, Numeric: - return Numeric - case TinyBlob, Blob, MediumBlob, LongBlob, Bytea, Binary, VarBinary: - return Blob - case Serial, BigSerial: - c.IsPrimaryKey = true - c.IsAutoIncrement = true - c.Nullable = false - return Integer - default: - return t - } -} - -func (db *ql) SupportInsertMany() bool { - return true -} - -func (db *ql) QuoteStr() string { - return "" -} - -func (db *ql) AutoIncrStr() string { - return "AUTOINCREMENT" -} - -func (db *ql) SupportEngine() bool { - return false -} - -func (db *ql) SupportCharset() bool { - return false -} - -func (db *ql) IndexOnTable() bool { - return false -} - -func (db *ql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - args := []interface{}{idxName} - return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args -} - -func (db *ql) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{tableName} - return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args -} - -func (db *ql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{tableName} - sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))" - return sql, args -} - -func (db *ql) GetColumns(tableName string) ([]string, map[string]*Column, error) { - args := []interface{}{tableName} - s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" - cnn, err := sql.Open(db.driverName, db.dataSourceName) - if err != nil { - return nil, nil, err - } - defer cnn.Close() - res, err := query(cnn, s, args...) - if err != nil { - return nil, nil, err - } - - var sql string - for _, record := range res { - for name, content := range record { - if name == "sql" { - sql = string(content) - } - } - } - - nStart := strings.Index(sql, "(") - nEnd := strings.Index(sql, ")") - colCreates := strings.Split(sql[nStart+1:nEnd], ",") - cols := make(map[string]*Column) - colSeq := make([]string, 0) - for _, colStr := range colCreates { - fields := strings.Fields(strings.TrimSpace(colStr)) - col := new(Column) - col.Indexes = make(map[string]bool) - col.Nullable = true - for idx, field := range fields { - if idx == 0 { - col.Name = strings.Trim(field, "`[] ") - continue - } else if idx == 1 { - col.SQLType = SQLType{field, 0, 0} - } - switch field { - case "PRIMARY": - col.IsPrimaryKey = true - case "AUTOINCREMENT": - col.IsAutoIncrement = true - case "NULL": - if fields[idx-1] == "NOT" { - col.Nullable = false - } else { - col.Nullable = true - } - } - } - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - return colSeq, cols, nil -} - -func (db *ql) GetTables() ([]*Table, error) { - args := []interface{}{} - s := "SELECT name FROM sqlite_master WHERE type='table'" - - cnn, err := sql.Open(db.driverName, db.dataSourceName) - if err != nil { - return nil, err - } - defer cnn.Close() - res, err := query(cnn, s, args...) - if err != nil { - return nil, err - } - - tables := make([]*Table, 0) - for _, record := range res { - table := new(Table) - for name, content := range record { - switch name { - case "name": - table.Name = string(content) - } - } - if table.Name == "sqlite_sequence" { - continue - } - tables = append(tables, table) - } - return tables, nil -} - -func (db *ql) GetIndexes(tableName string) (map[string]*Index, error) { - args := []interface{}{tableName} - s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?" - cnn, err := sql.Open(db.driverName, db.dataSourceName) - if err != nil { - return nil, err - } - defer cnn.Close() - res, err := query(cnn, s, args...) - if err != nil { - return nil, err - } - - indexes := make(map[string]*Index, 0) - for _, record := range res { - index := new(Index) - sql := string(record["sql"]) - - if sql == "" { - continue - } - - nNStart := strings.Index(sql, "INDEX") - nNEnd := strings.Index(sql, "ON") - if nNStart == -1 || nNEnd == -1 { - continue - } - - indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []") - //fmt.Println(indexName) - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - index.Name = indexName[5+len(tableName) : len(indexName)] - } else { - index.Name = indexName - } - - if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") { - index.Type = UniqueType - } else { - index.Type = IndexType - } - - nStart := strings.Index(sql, "(") - nEnd := strings.Index(sql, ")") - colIndexes := strings.Split(sql[nStart+1:nEnd], ",") - - index.Cols = make([]string, 0) - for _, col := range colIndexes { - index.Cols = append(index.Cols, strings.Trim(col, "` []")) - } - indexes[index.Name] = index - } - - return indexes, nil -} diff --git a/ql_test.go b/ql_test.go deleted file mode 100644 index 46d0104d..00000000 --- a/ql_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package xorm - -import ( - "database/sql" - "os" - "testing" - - _ "github.com/mattn/ql-driver" -) - -func newQlEngine() (*Engine, error) { - os.Remove("./ql.db") - return NewEngine("ql", "./ql.db") -} - -func newQlDriverDB() (*sql.DB, error) { - os.Remove("./ql.db") - return sql.Open("ql", "./ql.db") -} - -func TestQl(t *testing.T) { - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestQlWithCache(t *testing.T) { - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) -} - -const ( - createTableQl = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, `title` TEXT NULL, `age` TEXT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL);" - dropTableQl = "DROP TABLE IF EXISTS `big_struct`;" -) - -func BenchmarkQlDriverInsert(t *testing.B) { - doBenchDriver(newQlDriverDB, createTableQl, dropTableQl, - doBenchDriverInsert, t) -} - -func BenchmarkQlDriverFind(t *testing.B) { - doBenchDriver(newQlDriverDB, createTableQl, dropTableQl, - doBenchDriverFind, t) -} - -func BenchmarkQlNoCacheInsert(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchInsert(engine, t) -} - -func BenchmarkQlNoCacheFind(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkQlNoCacheFindPtr(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkQlCacheInsert(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) - doBenchInsert(engine, t) -} - -func BenchmarkQlCacheFind(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) - doBenchFind(engine, t) -} - -func BenchmarkQlCacheFindPtr(t *testing.B) { - t.StopTimer() - engine, err := newQlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000)) - doBenchFindPtr(engine, t) -} diff --git a/session.go b/session.go index 731027ce..10bba1bb 100644 --- a/session.go +++ b/session.go @@ -286,7 +286,7 @@ func (session *Session) Begin() error { // When using transaction, you can rollback if any error func (session *Session) Rollback() error { if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { - session.Engine.LogSQL("ROLL BACK") + session.Engine.LogSQL(session.Engine.dialect.RollBackStr()) session.IsCommitedOrRollbacked = true return session.Tx.Rollback() } diff --git a/statement.go b/statement.go index 80c5dccb..e4ea1a2c 100644 --- a/statement.go +++ b/statement.go @@ -25,7 +25,7 @@ type Statement struct { HavingStr string ColumnStr string columnMap map[string]bool - useAllCols bool + useAllCols bool OmitStr string ConditionStr string AltTableName string @@ -240,7 +240,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { // Auto generating conditions according a struct func buildConditions(engine *Engine, table *Table, bean interface{}, - includeVersion bool, includeUpdated bool, includeNil bool, + includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, allUseBool bool, useAllCols bool, boolColumnMap map[string]bool) ([]string, []interface{}) { @@ -712,13 +712,7 @@ func (s *Statement) genDelIndexSQL() []string { } func (s *Statement) genDropSQL() string { - if s.Engine.dialect.DBType() == MSSQL { - return "IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'" + - s.TableName() + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1) " + - "DROP TABLE " + s.Engine.Quote(s.TableName()) + ";" - } else { - return "DROP TABLE IF EXISTS " + s.Engine.Quote(s.TableName()) + ";" - } + return s.Engine.dialect.DropTableSql(s.TableName()) + ";" } func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) { @@ -766,7 +760,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{} statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, true, false, - true, statement.allUseBool, statement.useAllCols,statement.boolColumnMap) + true, statement.allUseBool, statement.useAllCols, statement.boolColumnMap) statement.ConditionStr = strings.Join(colNames, " AND ") statement.BeanArgs = args From a1e3dd8db0ec2440ccf13d5ac090a839e158cd8d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 5 Apr 2014 22:17:12 +0800 Subject: [PATCH 30/41] comment ql --- xorm.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xorm.go b/xorm.go index a4bded59..0a18d5e3 100644 --- a/xorm.go +++ b/xorm.go @@ -40,10 +40,6 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { } else if driverName == ORACLE_OCI { engine.dialect = &oracle{} engine.Filters = append(engine.Filters, &QuoteFilter{}) - } else if driverName == QL { - engine.dialect = &ql{} - engine.Filters = append(engine.Filters, &PgSeqFilter{}) - engine.Filters = append(engine.Filters, &QuoteFilter{}) } else { return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName)) } From 6e7cead1ec71ad5ea0369b86e1cdf9c64adaf883 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 5 Apr 2014 22:18:25 +0800 Subject: [PATCH 31/41] remove debug info --- engine.go | 1 - 1 file changed, 1 deletion(-) diff --git a/engine.go b/engine.go index 205ed873..a4d1912a 100644 --- a/engine.go +++ b/engine.go @@ -808,7 +808,6 @@ func (engine *Engine) Sync(beans ...interface{}) error { } } } else if index.Type == IndexType { - fmt.Println("index:", table.Name, name, index) isExist, err := session.isIndexExist2(table.Name, index.Cols, false) if err != nil { return err From 9d5f834eb2e8996509c6928a02fc73c935be63f6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 6 Apr 2014 12:58:16 +0800 Subject: [PATCH 32/41] bug fixed & add MustCols function & improved docs --- base_test.go | 57 ++++++++++++++++++++++++++++++++++++-- docs/QuickStart.md | 65 ++++++++++++++++++++++++++++++++------------ docs/QuickStartEn.md | 29 ++++++++++++++++---- engine.go | 12 ++++++++ session.go | 13 ++++++--- statement.go | 44 ++++++++++++++++++++++-------- 6 files changed, 179 insertions(+), 41 deletions(-) diff --git a/base_test.go b/base_test.go index 53d15bfc..3199b850 100644 --- a/base_test.go +++ b/base_test.go @@ -372,8 +372,8 @@ func update(engine *Engine, t *testing.T) { } type UpdateAllCols struct { - Id int64 - Bool bool + Id int64 + Bool bool String string } @@ -383,7 +383,7 @@ func update(engine *Engine, t *testing.T) { t.Error(err) panic(err) } - + _, err = engine.Insert(col1) if err != nil { t.Error(err) @@ -417,6 +417,57 @@ func update(engine *Engine, t *testing.T) { panic(err) return } + + { + type UpdateMustCols struct { + Id int64 + Bool bool + String string + } + + col1 := &UpdateMustCols{} + err = engine.Sync(col1) + if err != nil { + t.Error(err) + panic(err) + } + + _, err = engine.Insert(col1) + if err != nil { + t.Error(err) + panic(err) + } + + col2 := &UpdateMustCols{col1.Id, true, ""} + boolStr := engine.columnMapper.Obj2Table("Bool") + stringStr := engine.columnMapper.Obj2Table("String") + _, err = engine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2) + if err != nil { + t.Error(err) + panic(err) + } + + col3 := &UpdateMustCols{} + has, err := engine.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 + } + } } func updateSameMapper(engine *Engine, t *testing.T) { diff --git a/docs/QuickStart.md b/docs/QuickStart.md index dc2f0cd3..d787cb0b 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -4,7 +4,7 @@ xorm 快速入门 * [1.创建Orm引擎](#10) * [2.定义表结构体](#20) * [2.1.名称映射规则](#21) - * [2.2.前缀映射规则和后缀映射规则](#22) + * [2.2.前缀映射,后缀映射和缓存映射](#22) * [2.3.使用Table和Tag改变名称映射](#23) * [2.4.Column属性定义](#24) * [2.5.Go与字段类型对应表](#25) @@ -29,12 +29,13 @@ xorm 快速入门 * [9.执行SQL命令](#100) * [10.事务处理](#110) * [11.缓存](#120) -* [12.xorm工具](#130) - * [12.1.反转命令](#131) -* [13.Examples](#140) -* [14.案例](#150) -* [15.那些年我们踩过的坑](#160) -* [16.讨论](#170) +* [12.事件](#125) +* [13.xorm工具](#130) + * [13.1.反转命令](#131) +* [14.Examples](#140) +* [15.案例](#150) +* [16.那些年我们踩过的坑](#160) +* [17.讨论](#170) ## 1.创建Orm引擎 @@ -129,11 +130,11 @@ engine.SetColumnMapper(SnakeMapper{}) ``` -### 2.2.前缀映射规则和后缀映射规则 +### 2.2.前缀映射,后缀映射和缓存映射 * 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 * 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 -* +* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以组合其它的映射规则,起到在内存中缓存曾经映射过的命名映射。 ### 2.3.使用Table和Tag改变名称映射 @@ -153,7 +154,7 @@ type User struct { } ``` -对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。 +对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。对于使用者,一般只要使用自己熟悉的数据库字段定义即可。 具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写: @@ -407,7 +408,11 @@ engine.Cols("age", "name").Update(&user) // UPDATE user SET age=? AND name=? ``` -其中的参数"age", "name"也可以写成"age, name",两种写法均可 +* AllCols() +查询或更新所有字段。 + +* MustCols(…string) +某些字段必须更新。 * Omit(...string) 和cols相反,此函数指定排除某些指定的字段。注意:此方法和Cols方法不可同时使用 @@ -729,20 +734,46 @@ engine.ClearCache(new(User)) ![cache design](https://raw.github.com/lunny/xorm/master/docs/cache_design.png) + +## 12.事件 +xorm支持两种方式的事件,一种是在Struct中的特定方法来作为事件的方法,一种是在执行语句的过程中执行事件。 + +在Struct中作为成员方法的事件如下: + +* BeforeInsert() + +* BeforeUpdate() + +* BeforeDelete() + +* AfterInsert() + +* AfterUpdate() + +* AfterDelete() + +在语句执行过程中的事件方法为: + +* Before(beforeFunc interface{}) + +* After(afterFunc interface{}) + +其中beforeFunc和afterFunc的原型为func(bean interface{}). + -## 12.xorm工具 +## 13.xorm工具 xorm工具提供了xorm命令,能够帮助做很多事情。 -### 12.1.反转命令 +### 13.1.反转命令 参见 [xorm工具](https://github.com/lunny/xorm/tree/master/xorm) -## 13.Examples +## 14.Examples 请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples) -## 14.案例 +## 15.案例 * [Gowalker](http://gowalker.org),源代码 [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) @@ -753,7 +784,7 @@ xorm工具提供了xorm命令,能够帮助做很多事情。 * [VeryHour](http://veryhour.com) -## 15.那些年我们踩过的坑 +## 16.那些年我们踩过的坑 * 怎么同时使用xorm的tag和json的tag? 答:使用空格 @@ -797,5 +828,5 @@ money float64 `xorm:"Numeric"` -## 16.讨论 +## 17.讨论 请加入QQ群:280360085 进行讨论。 diff --git a/docs/QuickStartEn.md b/docs/QuickStartEn.md index 5249c81f..7cc08e2e 100644 --- a/docs/QuickStartEn.md +++ b/docs/QuickStartEn.md @@ -100,30 +100,47 @@ engine.Logger = f ## 2.Define struct -xorm支持将一个struct映射为数据库中对应的一张表。映射规则如下: +xorm map a struct to a database table, the rule is below. -### 2.1.名称映射规则 +### 2.1.name mapping rule -名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射。由xorm.IMapper接口的实现者来管理,xorm内置了两种IMapper实现:`SnakeMapper` 和 `SameMapper`。SnakeMapper支持struct为驼峰式命名,表结构为下划线命名之间的转换;SameMapper支持相同的命名。 +use xorm.IMapper interface to implement. There are two IMapper implemented: `SnakeMapper` and `SameMapper`. SnakeMapper means struct name is word by word and table name or column name as 下划线. SameMapper means same name between struct and table. -当前SnakeMapper为默认值,如果需要改变时,在engine创建完成后使用 +SnakeMapper is the default. ```Go engine.Mapper = SameMapper{} ``` +同时需要注意的是: + +* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 +* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: + +```Go +engine.SetTableMapper(SameMapper{}) +engine.SetColumnMapper(SnakeMapper{}) +``` + + +### 2.2.前缀映射规则,后缀映射规则和缓存映射规则 + +* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 +* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 +* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以起到在内存中缓存曾经映射过的命名映射。 + 当然,如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 -### 2.2.使用Table和Tag改变名称映射 +### 2.3.使用Table和Tag改变名称映射 如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。 通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。 -### 2.3.Column属性定义 +### 2.4.Column属性定义 我们在field对应的Tag中对Column的一些属性进行定义,定义的方法基本和我们写SQL定义表结构类似,比如: ``` diff --git a/engine.go b/engine.go index a4d1912a..070c718c 100644 --- a/engine.go +++ b/engine.go @@ -336,6 +336,18 @@ func (engine *Engine) Cols(columns ...string) *Session { return session.Cols(columns...) } +func (engine *Engine) AllCols() *Session { + session := engine.NewSession() + session.IsAutoClose = true + return session.AllCols() +} + +func (engine *Engine) MustCols(columns ...string) *Session { + session := engine.NewSession() + session.IsAutoClose = true + return session.MustCols(columns...) +} + // Xorm automatically retrieve condition according struct, but // if struct has bool field, it will ignore them. So use UseBool // to tell system to do not ignore them. diff --git a/session.go b/session.go index 10bba1bb..bc718b9b 100644 --- a/session.go +++ b/session.go @@ -131,6 +131,11 @@ func (session *Session) AllCols() *Session { return session } +func (session *Session) MustCols(columns ...string) *Session { + session.Statement.MustCols(columns...) + return session +} + func (session *Session) NoCascade() *Session { session.Statement.UseCascade = false return session @@ -1029,7 +1034,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) if len(condiBean) > 0 { colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true, false, true, session.Statement.allUseBool, session.Statement.useAllCols, - session.Statement.boolColumnMap) + session.Statement.mustColumnMap) session.Statement.ConditionStr = strings.Join(colNames, " AND ") session.Statement.BeanArgs = args } @@ -2845,7 +2850,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 if session.Statement.ColumnStr == "" { colNames, args = buildConditions(session.Engine, table, bean, false, false, false, false, session.Statement.allUseBool, session.Statement.useAllCols, - session.Statement.boolColumnMap) + session.Statement.mustColumnMap) } else { colNames, args, err = table.genCols(session, bean, true, true) if err != nil { @@ -2880,7 +2885,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 if len(condiBean) > 0 { condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true, false, true, session.Statement.allUseBool, session.Statement.useAllCols, - session.Statement.boolColumnMap) + session.Statement.mustColumnMap) } var condition = "" @@ -3069,7 +3074,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) { session.Statement.RefTable = table colNames, args := buildConditions(session.Engine, table, bean, true, true, false, true, session.Statement.allUseBool, session.Statement.useAllCols, - session.Statement.boolColumnMap) + session.Statement.mustColumnMap) var condition = "" diff --git a/statement.go b/statement.go index e4ea1a2c..805f5955 100644 --- a/statement.go +++ b/statement.go @@ -41,7 +41,7 @@ type Statement struct { IsDistinct bool allUseBool bool checkVersion bool - boolColumnMap map[string]bool + mustColumnMap map[string]bool inColumns map[string][]interface{} } @@ -70,7 +70,7 @@ func (statement *Statement) Init() { statement.UseAutoTime = true statement.IsDistinct = false statement.allUseBool = false - statement.boolColumnMap = make(map[string]bool) + statement.mustColumnMap = make(map[string]bool) statement.checkVersion = true statement.inColumns = make(map[string][]interface{}) } @@ -242,7 +242,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { func buildConditions(engine *Engine, table *Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, allUseBool bool, useAllCols bool, - boolColumnMap map[string]bool) ([]string, []interface{}) { + mustColumnMap map[string]bool) ([]string, []interface{}) { colNames := make([]string, 0) var args = make([]interface{}, 0) @@ -265,6 +265,14 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, fieldType := reflect.TypeOf(fieldValue.Interface()) requiredField := useAllCols + if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok { + if b { + requiredField = true + } else { + continue + } + } + if fieldType.Kind() == reflect.Ptr { if fieldValue.IsNil() { if includeNil { @@ -287,8 +295,6 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, case reflect.Bool: if allUseBool || requiredField { val = fieldValue.Interface() - } else if _, ok := boolColumnMap[col.Name]; ok { - val = fieldValue.Interface() } else { // if a bool in a struct, it will not be as a condition because it default is false, // please use Where() instead @@ -519,18 +525,34 @@ func (statement *Statement) Cols(columns ...string) *Statement { return statement } +// Update use only: update all columns func (statement *Statement) AllCols() *Statement { statement.useAllCols = true return statement } +// Update use only: must update columns +func (statement *Statement) MustCols(columns ...string) *Statement { + newColumns := col2NewCols(columns...) + for _, nc := range newColumns { + statement.mustColumnMap[strings.ToLower(nc)] = true + } + return statement +} + +// Update use only: not update columns +/*func (statement *Statement) NotCols(columns ...string) *Statement { + newColumns := col2NewCols(columns...) + for _, nc := range newColumns { + statement.mustColumnMap[strings.ToLower(nc)] = false + } + return statement +}*/ + // indicates that use bool fields as update contents and query contiditions func (statement *Statement) UseBool(columns ...string) *Statement { if len(columns) > 0 { - newColumns := col2NewCols(columns...) - for _, nc := range newColumns { - statement.boolColumnMap[strings.ToLower(nc)] = true - } + statement.MustCols(columns...) } else { statement.allUseBool = true } @@ -721,7 +743,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) colNames, args := buildConditions(statement.Engine, table, bean, true, true, false, true, statement.allUseBool, statement.useAllCols, - statement.boolColumnMap) + statement.mustColumnMap) statement.ConditionStr = strings.Join(colNames, " AND ") statement.BeanArgs = args @@ -760,7 +782,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{} statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, true, false, - true, statement.allUseBool, statement.useAllCols, statement.boolColumnMap) + true, statement.allUseBool, statement.useAllCols, statement.mustColumnMap) statement.ConditionStr = strings.Join(colNames, " AND ") statement.BeanArgs = args From 9b23e7d6c089c72ab9abeac334fd3f8bb4acb64f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Apr 2014 16:46:23 +0800 Subject: [PATCH 33/41] resolved #89: if struct has func, the struct's name is the result --- base_test.go | 24 +++++++++++++++++++++++ engine.go | 54 ++++++++++++++++++++++++++++++++++------------------ helpers.go | 7 ++++++- session.go | 24 ++++++++++++----------- statement.go | 7 ++++--- 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/base_test.go b/base_test.go index 3199b850..f8d9d794 100644 --- a/base_test.go +++ b/base_test.go @@ -3990,6 +3990,28 @@ func testCompositeKey2(engine *Engine, t *testing.T) { } } +type CustomTableName struct { + Id int64 + Name string +} + +func (c *CustomTableName) TableName() string { + return "customtablename" +} + +func testCustomTableName(engine *Engine, t *testing.T) { + c := new(CustomTableName) + err := engine.DropTables(c) + if err != nil { + t.Error(err) + } + + err = engine.CreateTables(c) + if err != nil { + t.Error(err) + } +} + func testAll(engine *Engine, t *testing.T) { fmt.Println("-------------- directCreateTable --------------") directCreateTable(engine, t) @@ -4100,6 +4122,8 @@ func testAll2(engine *Engine, t *testing.T) { testProcessors(engine, t) fmt.Println("-------------- transaction --------------") transaction(engine, t) + fmt.Println("-------------- testCustomTableName --------------") + testCustomTableName(engine, t) } // !nash! the 3rd set of the test is intended for non-cache enabled engine diff --git a/engine.go b/engine.go index 070c718c..2499d494 100644 --- a/engine.go +++ b/engine.go @@ -157,9 +157,9 @@ func (engine *Engine) NoCascade() *Session { // Set a table use a special cacher func (engine *Engine) MapCacher(bean interface{}, cacher Cacher) { - t := rType(bean) - engine.autoMapType(t) - engine.Tables[t].Cacher = cacher + v := rValue(bean) + engine.autoMapType(v) + engine.Tables[v.Type()].Cacher = cacher } // OpenDB provides a interface to operate database directly. @@ -435,12 +435,13 @@ func (engine *Engine) Having(conditions string) *Session { return session.Having(conditions) } -func (engine *Engine) autoMapType(t reflect.Type) *Table { +func (engine *Engine) autoMapType(v reflect.Value) *Table { + t := v.Type() engine.mutex.RLock() table, ok := engine.Tables[t] engine.mutex.RUnlock() if !ok { - table = engine.mapType(t) + table = engine.mapType(v) engine.mutex.Lock() engine.Tables[t] = table engine.mutex.Unlock() @@ -449,8 +450,8 @@ func (engine *Engine) autoMapType(t reflect.Type) *Table { } func (engine *Engine) autoMap(bean interface{}) *Table { - t := rType(bean) - return engine.autoMapType(t) + v := rValue(bean) + return engine.autoMapType(v) } func (engine *Engine) newTable() *Table { @@ -475,9 +476,24 @@ func addIndex(indexName string, table *Table, col *Column, indexType int) { } } -func (engine *Engine) mapType(t reflect.Type) *Table { +func (engine *Engine) mapType(v reflect.Value) *Table { + t := v.Type() table := engine.newTable() - table.Name = engine.tableMapper.Obj2Table(t.Name()) + method := v.MethodByName("TableName") + if !method.IsValid() { + method = v.Addr().MethodByName("TableName") + } + if method.IsValid() { + params := []reflect.Value{} + results := method.Call(params) + if len(results) == 1 { + table.Name = results[0].Interface().(string) + } + } + + if table.Name == "" { + table.Name = engine.tableMapper.Obj2Table(t.Name()) + } table.Type = t var idFieldColName string @@ -487,7 +503,8 @@ func (engine *Engine) mapType(t reflect.Type) *Table { tag := t.Field(i).Tag ormTagStr := tag.Get(engine.TagIdentifier) var col *Column - fieldType := t.Field(i).Type + fieldValue := v.Field(i) + fieldType := fieldValue.Type() if ormTagStr != "" { col = &Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false, @@ -500,7 +517,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } if (strings.ToUpper(tags[0]) == "EXTENDS") && (fieldType.Kind() == reflect.Struct) { - parentTable := engine.mapType(fieldType) + parentTable := engine.mapType(fieldValue) for name, col := range parentTable.Columns { col.FieldName = fmt.Sprintf("%v.%v", fieldType.Name(), col.FieldName) table.Columns[strings.ToLower(name)] = col @@ -671,19 +688,20 @@ func (engine *Engine) mapping(beans ...interface{}) (e error) { engine.mutex.Lock() defer engine.mutex.Unlock() for _, bean := range beans { - t := rType(bean) - engine.Tables[t] = engine.mapType(t) + v := rValue(bean) + engine.Tables[v.Type()] = engine.mapType(v) } return } // If a table has any reocrd func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) { - t := rType(bean) + v := rValue(bean) + t := v.Type() if t.Kind() != reflect.Struct { return false, errors.New("bean should be a struct or struct's point") } - engine.autoMapType(t) + engine.autoMapType(v) session := engine.NewSession() defer session.Close() rows, err := session.Count(bean) @@ -692,11 +710,11 @@ func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) { // If a table is exist func (engine *Engine) IsTableExist(bean interface{}) (bool, error) { - t := rType(bean) - if t.Kind() != reflect.Struct { + v := rValue(bean) + if v.Type().Kind() != reflect.Struct { return false, errors.New("bean should be a struct or struct's point") } - table := engine.autoMapType(t) + table := engine.autoMapType(v) session := engine.NewSession() defer session.Close() has, err := session.isTableExist(table.Name) diff --git a/helpers.go b/helpers.go index 96f118f2..25b6ddc8 100644 --- a/helpers.go +++ b/helpers.go @@ -37,9 +37,14 @@ func makeArray(elem string, count int) []string { return res } +func rValue(bean interface{}) reflect.Value { + return reflect.Indirect(reflect.ValueOf(bean)) +} + func rType(bean interface{}) reflect.Type { sliceValue := reflect.Indirect(reflect.ValueOf(bean)) - return reflect.TypeOf(sliceValue.Interface()) + //return reflect.TypeOf(sliceValue.Interface()) + return sliceValue.Type() } func structName(v reflect.Type) string { diff --git a/session.go b/session.go index bc718b9b..b8035acc 100644 --- a/session.go +++ b/session.go @@ -358,12 +358,12 @@ func cleanupProcessorsClosures(slices *[]func(interface{})) { } func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error { - dataStruct := reflect.Indirect(reflect.ValueOf(obj)) + dataStruct := rValue(obj) if dataStruct.Kind() != reflect.Struct { return errors.New("Expected a pointer to a struct") } - table := session.Engine.autoMapType(rType(obj)) + table := session.Engine.autoMapType(dataStruct) for key, data := range objMap { key = strings.ToLower(key) @@ -1017,12 +1017,14 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) if session.Statement.RefTable == nil { if sliceElementType.Kind() == reflect.Ptr { if sliceElementType.Elem().Kind() == reflect.Struct { - table = session.Engine.autoMapType(sliceElementType.Elem()) + pv := reflect.New(sliceElementType.Elem()) + table = session.Engine.autoMapType(pv.Elem()) } else { return errors.New("slice type") } } else if sliceElementType.Kind() == reflect.Struct { - table = session.Engine.autoMapType(sliceElementType) + pv := reflect.New(sliceElementType) + table = session.Engine.autoMapType(pv.Elem()) } else { return errors.New("slice type") } @@ -1386,13 +1388,12 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *T } func (session *Session) row2Bean(rows *sql.Rows, fields []string, fieldsCount int, bean interface{}) error { - - dataStruct := reflect.Indirect(reflect.ValueOf(bean)) + dataStruct := rValue(bean) if dataStruct.Kind() != reflect.Struct { return errors.New("Expected a pointer to a struct") } - table := session.Engine.autoMapType(rType(bean)) + table := session.Engine.autoMapType(dataStruct) var scanResultContainers []interface{} for i := 0; i < fieldsCount; i++ { @@ -1494,7 +1495,7 @@ func (session *Session) row2Bean(rows *sql.Rows, fields []string, fieldsCount in fieldValue.Set(vv) } } else if session.Statement.UseCascade { - table := session.Engine.autoMapType(fieldValue.Type()) + table := session.Engine.autoMapType(*fieldValue) if table != nil { var x int64 if rawValueType.Kind() == reflect.Int64 { @@ -1763,9 +1764,10 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error } bean := sliceValue.Index(0).Interface() - sliceElementType := rType(bean) + elementValue := rValue(bean) + //sliceElementType := elementValue.Type() - table := session.Engine.autoMapType(sliceElementType) + table := session.Engine.autoMapType(elementValue) session.Statement.RefTable = table size := sliceValue.Len() @@ -2073,7 +2075,7 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data v = x fieldValue.Set(reflect.ValueOf(v)) } else if session.Statement.UseCascade { - table := session.Engine.autoMapType(fieldValue.Type()) + table := session.Engine.autoMapType(*fieldValue) if table != nil { x, err := strconv.ParseInt(string(data), 10, 64) if err != nil { diff --git a/statement.go b/statement.go index 805f5955..773dd378 100644 --- a/statement.go +++ b/statement.go @@ -113,11 +113,12 @@ func (statement *Statement) Or(querystring string, args ...interface{}) *Stateme // tempororily set table name func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { - t := rType(tableNameOrBean) + v := rValue(tableNameOrBean) + t := v.Type() if t.Kind() == reflect.String { statement.AltTableName = tableNameOrBean.(string) } else if t.Kind() == reflect.Struct { - statement.RefTable = statement.Engine.autoMapType(t) + statement.RefTable = statement.Engine.autoMapType(v) } return statement } @@ -342,7 +343,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, val = t } } else { - engine.autoMapType(fieldValue.Type()) + engine.autoMapType(fieldValue) if table, ok := engine.Tables[fieldValue.Type()]; ok { if len(table.PrimaryKeys) == 1 { pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName) From 61813611169ae385bb2bca36e74015d774e4bd35 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Apr 2014 16:50:43 +0800 Subject: [PATCH 34/41] docs added TableName --- docs/QuickStart.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/QuickStart.md b/docs/QuickStart.md index d787cb0b..c00e9727 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -141,7 +141,9 @@ engine.SetColumnMapper(SnakeMapper{}) 如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。 -通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。 +* 如果struct拥有`Tablename() string`的成员方法,那么此方法的返回值即是该struct默认对应的数据库表名。 + +* 通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。 ### 2.4.Column属性定义 From 128db9c7922b7262600392fb5300995704071cd6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 11 Apr 2014 17:04:39 +0800 Subject: [PATCH 35/41] bug fixed and tests passed --- engine.go | 3 +-- tests/base_test.go | 20 ++++++++++---------- tests/benchmark_base_test.go | 2 +- tests/mssql_test.go | 4 ++-- tests/mymysql_test.go | 4 ++-- tests/mysql_test.go | 6 +++--- tests/postgres_test.go | 6 +++--- tests/sqlite3_test.go | 6 +++--- 8 files changed, 25 insertions(+), 26 deletions(-) diff --git a/engine.go b/engine.go index ca1eb522..0f4caacf 100644 --- a/engine.go +++ b/engine.go @@ -589,8 +589,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { col.Name = key } } - panic("broken") - //engine.dialect.SqlType(col) + engine.dialect.SqlType(col) } preKey = k } diff --git a/tests/base_test.go b/tests/base_test.go index c0c37015..4f5704a8 100644 --- a/tests/base_test.go +++ b/tests/base_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/lunny/xorm" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" ) /* @@ -442,8 +442,8 @@ func update(engine *xorm.Engine, t *testing.T) { } col2 := &UpdateMustCols{col1.Id, true, ""} - boolStr := engine.columnMapper.Obj2Table("Bool") - stringStr := engine.columnMapper.Obj2Table("String") + boolStr := engine.ColumnMapper.Obj2Table("Bool") + stringStr := engine.ColumnMapper.Obj2Table("String") _, err = engine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2) if err != nil { t.Error(err) @@ -746,7 +746,8 @@ func in(engine *xorm.Engine, t *testing.T) { users = make([]Userinfo, 0) ids := []interface{}{7, 8, 9} - err = engine.Where("departname = ?", "dev").In("(id)", ids...).Find(&users) + department := engine.ColumnMapper.Obj2Table("Departname") + err = engine.Where("`"+department+"` = ?", "dev").In("(id)", ids...).Find(&users) if err != nil { t.Error(err) panic(err) @@ -767,7 +768,6 @@ func in(engine *xorm.Engine, t *testing.T) { } } - department := engine.ColumnMapper.Obj2Table("Departname") dev := engine.ColumnMapper.Obj2Table("Dev") err = engine.In("(id)", 1).In("(id)", 2).In(department, dev).Find(&users) @@ -3918,9 +3918,9 @@ type Lowercase struct { ended int64 `xorm:"-"` } -func testLowerCase(engine *Engine, t *testing.T) { +func testLowerCase(engine *xorm.Engine, t *testing.T) { err := engine.Sync(&Lowercase{}) - _, err = engine.Where("id > 0").Delete(&Lowercase{}) + _, err = engine.Where("(id) > 0").Delete(&Lowercase{}) if err != nil { t.Error(err) panic(err) @@ -4019,7 +4019,7 @@ func (c *CustomTableName) TableName() string { return "customtablename" } -func testCustomTableName(engine *Engine, t *testing.T) { +func testCustomTableName(engine *xorm.Engine, t *testing.T) { c := new(CustomTableName) err := engine.DropTables(c) if err != nil { @@ -4032,7 +4032,7 @@ func testCustomTableName(engine *Engine, t *testing.T) { } } -func testAll(engine *Engine, t *testing.T) { +func testAll(engine *xorm.Engine, t *testing.T) { fmt.Println("-------------- directCreateTable --------------") directCreateTable(engine, t) fmt.Println("-------------- insert --------------") diff --git a/tests/benchmark_base_test.go b/tests/benchmark_base_test.go index 5570fa39..d970bd13 100644 --- a/tests/benchmark_base_test.go +++ b/tests/benchmark_base_test.go @@ -4,7 +4,7 @@ import ( "database/sql" "testing" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" ) type BigStruct struct { diff --git a/tests/mssql_test.go b/tests/mssql_test.go index e814d855..fac774e1 100644 --- a/tests/mssql_test.go +++ b/tests/mssql_test.go @@ -7,9 +7,9 @@ import ( "database/sql" "testing" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" _ "github.com/lunny/godbc" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" ) const mssqlConnStr = "driver={SQL Server};Server=192.168.20.135;Database=xorm_test; uid=sa; pwd=1234;" diff --git a/tests/mymysql_test.go b/tests/mymysql_test.go index 5646f95c..ef212a2c 100644 --- a/tests/mymysql_test.go +++ b/tests/mymysql_test.go @@ -4,8 +4,8 @@ import ( "database/sql" "testing" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" _ "github.com/ziutek/mymysql/godrv" ) diff --git a/tests/mysql_test.go b/tests/mysql_test.go index 38eebc55..02a70b39 100644 --- a/tests/mysql_test.go +++ b/tests/mysql_test.go @@ -5,9 +5,9 @@ import ( "testing" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" ) /* diff --git a/tests/postgres_test.go b/tests/postgres_test.go index 85e926cc..8abee32f 100644 --- a/tests/postgres_test.go +++ b/tests/postgres_test.go @@ -4,10 +4,10 @@ import ( "database/sql" "testing" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" _ "github.com/lib/pq" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" - "github.com/lunny/xorm/core" ) //var connStr string = "dbname=xorm_test user=lunny password=1234 sslmode=disable" diff --git a/tests/sqlite3_test.go b/tests/sqlite3_test.go index 1f982e29..18cc84a3 100644 --- a/tests/sqlite3_test.go +++ b/tests/sqlite3_test.go @@ -5,9 +5,9 @@ import ( "os" "testing" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" _ "github.com/mattn/go-sqlite3" ) From 1213bc14b598327c23ab49889a78999ca3c196f4 Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Fri, 11 Apr 2014 17:16:43 +0800 Subject: [PATCH 36/41] renamed import path --- .gopmfile | 2 +- CONTRIBUTING.md | 6 +- README.md | 20 ++-- README_CN.md | 18 ++-- doc.go | 4 +- docs/Changelog.md | 24 ++--- docs/ChangelogCN.md | 8 +- docs/QuickStart.md | 22 ++-- docs/QuickStartEn.md | 204 ++++++++++++++++++------------------- examples/cache.go | 4 +- examples/cachegoroutine.go | 2 +- examples/conversion.go | 2 +- examples/derive.go | 2 +- examples/goroutine.go | 2 +- examples/maxconnect.go | 2 +- examples/pool.go | 2 +- examples/singlemapping.go | 2 +- examples/sync.go | 2 +- xorm/.gopmfile | 2 +- xorm/README.md | 4 +- xorm/c++.go | 2 +- xorm/go.go | 2 +- xorm/lang.go | 2 +- xorm/reverse.go | 4 +- xorm/shell.go | 2 +- 25 files changed, 173 insertions(+), 173 deletions(-) diff --git a/.gopmfile b/.gopmfile index 3590b536..ecd6e20e 100644 --- a/.gopmfile +++ b/.gopmfile @@ -1,2 +1,2 @@ [target] -path = github.com/lunny/xorm \ No newline at end of file +path = github.com/go-xorm/xorm \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f65c2ae..fcbf9e31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,11 +21,11 @@ We appreciate any bug reports, but especially ones with self-contained further) test cases. It's especially helpful if you can submit a pull request with just the failing test case (you'll probably want to pattern it after the tests in -[base_test.go](https://github.com/lunny/xorm/blob/master/base_test.go) AND -[benchmark_base_test.go](https://github.com/lunny/xorm/blob/master/benchmark_base_test.go). +[base_test.go](https://github.com/go-xorm/xorm/blob/master/base_test.go) AND +[benchmark_base_test.go](https://github.com/go-xorm/xorm/blob/master/benchmark_base_test.go). If you implements a new database interface, you maybe need to add a _test.go file. -For example, [mysql_test.go](https://github.com/lunny/xorm/blob/master/mysql_test.go) +For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/mysql_test.go) ### New functionality diff --git a/README.md b/README.md index 4f85368b..ec56f0b3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -[中文](https://github.com/lunny/xorm/blob/master/README_CN.md) +[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md) Xorm is a simple and powerful ORM for Go. -[![Build Status](https://drone.io/github.com/lunny/xorm/status.png)](https://drone.io/github.com/lunny/xorm/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/lunny/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge") +[![Build Status](https://drone.io/github.com/go-xorm/xorm/status.png)](https://drone.io/github.com/go-xorm/xorm/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge") # Features @@ -18,7 +18,7 @@ Xorm is a simple and powerful ORM for Go. * Query Cache speed up -* Database Reverse support, See [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md) +* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md) * Simple cascade loading support @@ -54,25 +54,25 @@ Drivers for Go's sql package which currently support database/sql includes: * Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type * Performance improvement for Get()/Find()/Iterate() -[More changelogs ...](https://github.com/lunny/xorm/blob/master/docs/Changelog.md) +[More changelogs ...](https://github.com/go-xorm/xorm/blob/master/docs/Changelog.md) # Installation If you have [gopm](https://github.com/gpmgo/gopm) installed, - gopm get github.com/lunny/xorm + gopm get github.com/go-xorm/xorm Or - go get github.com/lunny/xorm + go get github.com/go-xorm/xorm # Documents -* [GoDoc](http://godoc.org/github.com/lunny/xorm) +* [GoDoc](http://godoc.org/github.com/go-xorm/xorm) -* [GoWalker](http://gowalker.org/github.com/lunny/xorm) +* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm) -* [Quick Start](https://github.com/lunny/xorm/blob/master/docs/QuickStartEn.md) +* [Quick Start](https://github.com/go-xorm/xorm/blob/master/docs/QuickStartEn.md) # Cases @@ -96,7 +96,7 @@ Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xor # Contributors -If you want to pull request, please see [CONTRIBUTING](https://github.com/lunny/xorm/blob/master/CONTRIBUTING.md) +If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md) * [Lunny](https://github.com/lunny) * [Nashtsai](https://github.com/nashtsai) diff --git a/README_CN.md b/README_CN.md index 35b7ed70..ca43aa86 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,10 +1,10 @@ # xorm -[English](https://github.com/lunny/xorm/blob/master/README.md) +[English](https://github.com/go-xorm/xorm/blob/master/README.md) xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 -[![Build Status](https://drone.io/github.com/lunny/xorm/status.png)](https://drone.io/github.com/lunny/xorm/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/lunny/xorm) +[![Build Status](https://drone.io/github.com/go-xorm/xorm/status.png)](https://drone.io/github.com/go-xorm/xorm/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) ## 特性 @@ -56,25 +56,25 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 * 查询函数 Get()/Find()/Iterate() 在性能上的改进 -[更多更新日志...](https://github.com/lunny/xorm/blob/master/docs/ChangelogCN.md) +[更多更新日志...](https://github.com/go-xorm/xorm/blob/master/docs/ChangelogCN.md) ## 安装 推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装: - gopm get github.com/lunny/xorm + gopm get github.com/go-xorm/xorm 或者您也可以使用go工具进行安装: - go get github.com/lunny/xorm + go get github.com/go-xorm/xorm ## 文档 -* [快速开始](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md) +* [快速开始](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md) -* [GoWalker代码文档](http://gowalker.org/github.com/lunny/xorm) +* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm) -* [Godoc代码文档](http://godoc.org/github.com/lunny/xorm) +* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm) ## 案例 @@ -99,7 +99,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 # 贡献者 -如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/lunny/xorm/blob/master/CONTRIBUTING.md) +如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md) * [Lunny](https://github.com/lunny) * [Nashtsai](https://github.com/nashtsai) diff --git a/doc.go b/doc.go index 16d0b3a7..b183e8d2 100644 --- a/doc.go +++ b/doc.go @@ -9,7 +9,7 @@ Installation Make sure you have installed Go 1.1+ and then: - go get github.com/lunny/xorm + go get github.com/go-xorm/xorm Create Engine @@ -137,6 +137,6 @@ The above 7 methods could use with condition methods. engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find() //SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id -More usage, please visit https://github.com/lunny/xorm/blob/master/docs/QuickStartEn.md +More usage, please visit https://github.com/go-xorm/xorm/blob/master/docs/QuickStartEn.md */ package xorm diff --git a/docs/Changelog.md b/docs/Changelog.md index aeeccbbe..e3f5a05c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,20 +11,20 @@ Improvements: * Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type - * Performance improvement for Get()/Find()/Iterate() + * Performance improvement for Get()/Find()/Iterate() * **v0.2.3** : Improved documents; Optimistic Locking support; Timestamp with time zone support; Mapper change to tableMapper and columnMapper & added PrefixMapper & SuffixMapper support custom table or column name's prefix and suffix;Insert now return affected, err instead of id, err; Added UseBool & Distinct; * **v0.2.2** : Postgres drivers now support lib/pq; Added method Iterate for record by record to handler;Added SetMaxConns(go1.2+) support; some bugs fixed. -* **v0.2.1** : Added database reverse tool, now support generate go & c++ codes, see [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md); some bug fixed. -* **v0.2.0** : Added Cache supported, select is speeder up 3~5x; Added SameMapper for same name between struct and table; Added Sync method for auto added tables, columns, indexes; -* **v0.1.9** : Added postgres and mymysql supported; Added ` and ? supported on Raw SQL even if postgres; Added Cols, StoreEngine, Charset function, Added many column data type supported, please see [Mapping Rules](#mapping). -* **v0.1.8** : Added union index and union unique supported, please see [Mapping Rules](#mapping). -* **v0.1.7** : Added IConnectPool interface and NoneConnectPool, SysConnectPool, SimpleConnectPool the three implements. You can choose one of them and the default is SysConnectPool. You can customrize your own connection pool. struct Engine added Close method, It should be invoked before system exit. -* **v0.1.6** : Added conversion interface support; added struct derive support; added single mapping support -* **v0.1.5** : Added multi threads support; added Sql() function for struct query; Get function changed return inteface; MakeSession and Create are instead with NewSession and NewEngine. -* **v0.1.4** : Added simple cascade load support; added more data type supports. -* **v0.1.3** : Find function now supports both slice and map; Add Table function for multi tables and temperory tables support -* **v0.1.2** : Insert function now supports both struct and slice pointer parameters, batch inserting and auto transaction -* **v0.1.1** : Add Id, In functions and improved README +* **v0.2.1** : Added database reverse tool, now support generate go & c++ codes, see [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); some bug fixed. +* **v0.2.0** : Added Cache supported, select is speeder up 3~5x; Added SameMapper for same name between struct and table; Added Sync method for auto added tables, columns, indexes; +* **v0.1.9** : Added postgres and mymysql supported; Added ` and ? supported on Raw SQL even if postgres; Added Cols, StoreEngine, Charset function, Added many column data type supported, please see [Mapping Rules](#mapping). +* **v0.1.8** : Added union index and union unique supported, please see [Mapping Rules](#mapping). +* **v0.1.7** : Added IConnectPool interface and NoneConnectPool, SysConnectPool, SimpleConnectPool the three implements. You can choose one of them and the default is SysConnectPool. You can customrize your own connection pool. struct Engine added Close method, It should be invoked before system exit. +* **v0.1.6** : Added conversion interface support; added struct derive support; added single mapping support +* **v0.1.5** : Added multi threads support; added Sql() function for struct query; Get function changed return inteface; MakeSession and Create are instead with NewSession and NewEngine. +* **v0.1.4** : Added simple cascade load support; added more data type supports. +* **v0.1.3** : Find function now supports both slice and map; Add Table function for multi tables and temperory tables support +* **v0.1.2** : Insert function now supports both struct and slice pointer parameters, batch inserting and auto transaction +* **v0.1.1** : Add Id, In functions and improved README * **v0.1.0** : Inital release. \ No newline at end of file diff --git a/docs/ChangelogCN.md b/docs/ChangelogCN.md index 3786eba9..fef0bca7 100644 --- a/docs/ChangelogCN.md +++ b/docs/ChangelogCN.md @@ -15,10 +15,10 @@ * **v0.2.3** : 改善了文档;提供了乐观锁支持;添加了带时区时间字段支持;Mapper现在分成表名Mapper和字段名Mapper,同时实现了表或字段的自定义前缀后缀;Insert方法的返回值含义从id, err更改为 affected, err,请大家注意;添加了UseBool 和 Distinct函数。 * **v0.2.2** : Postgres驱动新增了对lib/pq的支持;新增了逐条遍历方法Iterate;新增了SetMaxConns(go1.2+)支持,修复了bug若干; -* **v0.2.1** : 新增数据库反转工具,当前支持go和c++代码的生成,详见 [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md); 修复了一些bug. -* **v0.2.0** : 新增 [缓存](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#120)支持,查询速度提升3-5倍; 新增数据库表和Struct同名的映射方式; 新增Sync同步表结构; -* **v0.1.9** : 新增 postgres 和 mymysql 驱动支持; 在Postgres中支持原始SQL语句中使用 ` 和 ? 符号; 新增Cols, StoreEngine, Charset 函数;SQL语句打印支持io.Writer接口,默认打印到控制台;新增更多的字段类型支持,详见 [映射规则](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#21);删除废弃的MakeSession和Create函数。 -* **v0.1.8** : 新增联合index,联合unique支持,请查看 [映射规则](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#21)。 +* **v0.2.1** : 新增数据库反转工具,当前支持go和c++代码的生成,详见 [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); 修复了一些bug. +* **v0.2.0** : 新增 [缓存](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#120)支持,查询速度提升3-5倍; 新增数据库表和Struct同名的映射方式; 新增Sync同步表结构; +* **v0.1.9** : 新增 postgres 和 mymysql 驱动支持; 在Postgres中支持原始SQL语句中使用 ` 和 ? 符号; 新增Cols, StoreEngine, Charset 函数;SQL语句打印支持io.Writer接口,默认打印到控制台;新增更多的字段类型支持,详见 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#21);删除废弃的MakeSession和Create函数。 +* **v0.1.8** : 新增联合index,联合unique支持,请查看 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#21)。 * **v0.1.7** : 新增IConnectPool接口以及NoneConnectPool, SysConnectPool, SimpleConnectPool三种实现,可以选择不使用连接池,使用系统连接池和使用自带连接池三种实现,默认为SysConnectPool,即系统自带的连接池。同时支持自定义连接池。Engine新增Close方法,在系统退出时应调用此方法。 * **v0.1.6** : 新增Conversion,支持自定义类型到数据库类型的转换;新增查询结构体自动检测匿名成员支持;新增单向映射支持; * **v0.1.5** : 新增对多线程的支持;新增Sql()函数;支持任意sql语句的struct查询;Get函数返回值变动;MakeSession和Create函数被NewSession和NewEngine函数替代; diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 12443a5f..2fc373a7 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -45,7 +45,7 @@ xorm 快速入门 ```Go import ( _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" ) engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8") defer engine.Close() @@ -56,7 +56,7 @@ or ```Go import ( _ "github.com/mattn/go-sqlite3" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" ) engine, err = xorm.NewEngine("sqlite3", "./test.db") defer engine.Close() @@ -125,9 +125,9 @@ engine.SetMapper(SameMapper{}) 同时需要注意的是: <<<<<<< HEAD -* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 +* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 * 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: - + ======= * 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 * 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: @@ -169,7 +169,7 @@ type User struct { } ``` -对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。对于使用者,一般只要使用自己熟悉的数据库字段定义即可。 +对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。对于使用者,一般只要使用自己熟悉的数据库字段定义即可。 具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写: @@ -181,7 +181,7 @@ type User struct { pk是否是Primary Key,如果在一个struct中有多个字段都使用了此标记,则这多个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7种Go的数据类型,复合主键支持这7种Go的数据类型的组合。 - 当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)字段类型 + 当前支持30多种字段类型,详情参见 [字段类型](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)字段类型 autoincr是否是自增 @@ -227,7 +227,7 @@ type User struct { - 2.string类型默认映射为varchar(255),如果需要不同的定义,可以在tag中自定义 -- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。具体参见 [go类型<->数据库类型对应表](https://github.com/lunny/xorm/blob/master/docs/AutoMap.md) +- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。具体参见 [go类型<->数据库类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/AutoMap.md) - 4.实现了Conversion接口的类型或者结构体,将根据接口的转换方式在类型和数据库记录之间进行相互转换。 ```Go @@ -242,7 +242,7 @@ type Conversion interface { 如果不使用tag来定义field对应的数据库字段类型,那么系统会自动给出一个默认的字段类型,对应表如下: -[go类型<->数据库类型对应表](https://github.com/lunny/xorm/blob/master/docs/AutoMap.md) +[go类型<->数据库类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/AutoMap.md) ## 3.表结构操作 @@ -755,7 +755,7 @@ engine.ClearCache(new(User)) 缓存的实现原理如下图所示: -![cache design](https://raw.github.com/lunny/xorm/master/docs/cache_design.png) +![cache design](https://raw.github.com/go-xorm/xorm/master/docs/cache_design.png) ## 12.事件 @@ -788,12 +788,12 @@ xorm支持两种方式的事件,一种是在Struct中的特定方法来作为 xorm工具提供了xorm命令,能够帮助做很多事情。 ### 13.1.反转命令 -参见 [xorm工具](https://github.com/lunny/xorm/tree/master/xorm) +参见 [xorm工具](https://github.com/go-xorm/xorm/tree/master/xorm) ## 14.Examples -请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples) +请访问[https://github.com/go-xorm/xorm/tree/master/examples](https://github.com/go-xorm/xorm/tree/master/examples) ## 15.案例 diff --git a/docs/QuickStartEn.md b/docs/QuickStartEn.md index 7cc08e2e..a8dce7cc 100644 --- a/docs/QuickStartEn.md +++ b/docs/QuickStartEn.md @@ -41,8 +41,8 @@ When using xorm, you can create multiple orm engines, an engine means a databse. ```Go import ( _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" -) + "github.com/go-xorm/xorm" +) engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8") defer engine.Close() ``` @@ -52,18 +52,18 @@ or ```Go import ( _ "github.com/mattn/go-sqlite3" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" ) engine, err = xorm.NewEngine("sqlite3", "./test.db") -defer engine.Close() +defer engine.Close() ``` Generally, you can only create one engine. Engine supports run on go rutines. xorm supports four drivers now: -* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) - +* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) + * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) * SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) @@ -95,7 +95,7 @@ engine.Logger = f 3.Engine support connection pool. The default pool is database/sql's and also you can use custom pool. Xorm provides two connection pool `xorm.NonConnectionPool` & `xorm.SimpleConnectPool`. If you want to use yourself pool, you can use `engine.SetPool` to set it. * Use `engine.SetIdleConns()` to set idle connections. -* Use `engine.SetMaxConns()` to set Max connections. This methods support only Go 1.2+. +* Use `engine.SetMaxConns()` to set Max connections. This methods support only Go 1.2+. ## 2.Define struct @@ -150,7 +150,7 @@ type User struct { } ``` -对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。 +对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。 具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写: @@ -162,7 +162,7 @@ type User struct { pk是否是Primary Key,当前仅支持int64类型 - 当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)字段类型 + 当前支持30多种字段类型,详情参见 [字段类型](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)字段类型 autoincr是否是自增 @@ -216,7 +216,7 @@ type Conversion interface { FromDB([]byte) error ToDB() ([]byte, error) } -``` +``` ## 3.表结构操作 @@ -264,7 +264,7 @@ xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到 调用方法如下: ```Go err := engine.Sync(new(User)) -``` +``` ## 4.插入数据 @@ -425,59 +425,59 @@ Having的参数字符串 当从一个struct来生成查询条件或更新字段时,xorm会判断struct的field是否为0,"",nil,如果为以上则不当做查询条件或者更新内容。因为bool类型只有true和false两种值,因此默认所有bool类型不会作为查询条件或者更新字段。如果可以使用此方法,如果默认不传参数,则所有的bool字段都将会被使用,如果参数不为空,则参数中指定的为字段名,则这些字段对应的bool值将被使用。 * Cascade(bool) -是否自动关联查询field中的数据,如果struct的field也是一个struct并且映射为某个Id,则可以在查询时自动调用Get方法查询出对应的数据。 +是否自动关联查询field中的数据,如果struct的field也是一个struct并且映射为某个Id,则可以在查询时自动调用Get方法查询出对应的数据。 -### 5.3.Get one record -Fetch a single object by user - -```Go -var user = User{Id:27} -has, err := engine.Get(&user) -// or has, err := engine.Id(27).Get(&user) - -var user = User{Name:"xlw"} -has, err := engine.Get(&user) -``` +### 5.3.Get one record +Fetch a single object by user + +```Go +var user = User{Id:27} +has, err := engine.Get(&user) +// or has, err := engine.Id(27).Get(&user) + +var user = User{Name:"xlw"} +has, err := engine.Get(&user) +``` -### 5.4.Find -Fetch multipe objects into a slice or a map, use Find: - -```Go -var everyone []Userinfo -err := engine.Find(&everyone) - -users := make(map[int64]Userinfo) -err := engine.Find(&users) -``` - -* also you can use Where, Limit - -```Go -var allusers []Userinfo -err := engine.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20 -``` - -* or you can use a struct query - -```Go -var tenusers []Userinfo -err := engine.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 offset 0 -``` - -* or In function - -```Go -var tenusers []Userinfo -err := engine.In("id", 1, 3, 5).Find(&tenusers) //Get All id in (1, 3, 5) -``` - -* The default will query all columns of a table. Use Cols function if you want to select some columns - -```Go -var tenusers []Userinfo -err := engine.Cols("id", "name").Find(&tenusers) //Find only id and name +### 5.4.Find +Fetch multipe objects into a slice or a map, use Find: + +```Go +var everyone []Userinfo +err := engine.Find(&everyone) + +users := make(map[int64]Userinfo) +err := engine.Find(&users) +``` + +* also you can use Where, Limit + +```Go +var allusers []Userinfo +err := engine.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20 +``` + +* or you can use a struct query + +```Go +var tenusers []Userinfo +err := engine.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 offset 0 +``` + +* or In function + +```Go +var tenusers []Userinfo +err := engine.In("id", 1, 3, 5).Find(&tenusers) //Get All id in (1, 3, 5) +``` + +* The default will query all columns of a table. Use Cols function if you want to select some columns + +```Go +var tenusers []Userinfo +err := engine.Cols("id", "name").Find(&tenusers) //Find only id and name ``` @@ -542,44 +542,44 @@ engine.Id(1).Get(&user) engine.Id(1).Update(&user) // UPDATE user SET ..., version = version + 1 WHERE id = ? AND version = ? ``` - + -## 7.Delete one or more records -Delete one or more records +## 7.Delete one or more records +Delete one or more records * delete by id - -```Go -err := engine.Id(1).Delete(&User{}) + +```Go +err := engine.Id(1).Delete(&User{}) ``` - + * delete by other conditions ```Go err := engine.Delete(&User{Name:"xlw"}) -``` +``` - -## 8.Execute SQL query - -Of course, SQL execution is also provided. - -If select then use Query - -```Go -sql := "select * from userinfo" -results, err := engine.Query(sql) -``` + +## 8.Execute SQL query - -## 9.Execute SQL command -If insert, update or delete then use Exec - -```Go -sql = "update userinfo set username=? where id=?" -res, err := engine.Exec(sql, "xiaolun", 1) -``` +Of course, SQL execution is also provided. + +If select then use Query + +```Go +sql := "select * from userinfo" +results, err := engine.Query(sql) +``` + + +## 9.Execute SQL command +If insert, update or delete then use Exec + +```Go +sql = "update userinfo set username=? where id=?" +res, err := engine.Exec(sql, "xiaolun", 1) +``` ## 10.Transaction @@ -613,8 +613,8 @@ if err != nil { err = session.Commit() if err != nil { return -} -``` +} +``` ## 11.缓存 @@ -654,19 +654,19 @@ engine.ClearCache(new(User)) Cache implement theory below: -![cache design](https://raw.github.com/lunny/xorm/master/docs/cache_design.png) +![cache design](https://raw.github.com/go-xorm/xorm/master/docs/cache_design.png) ## 12.xorm tool xorm工具提供了xorm命令,能够帮助做很多事情。 ### 12.1.Reverse command -Please visit [xorm tool](https://github.com/lunny/xorm/tree/master/xorm) +Please visit [xorm tool](https://github.com/go-xorm/xorm/tree/master/xorm) ## 13.Examples -请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples) +请访问[https://github.com/go-xorm/xorm/tree/master/examples](https://github.com/go-xorm/xorm/tree/master/examples) ## 14.Cases @@ -680,14 +680,14 @@ Please visit [xorm tool](https://github.com/lunny/xorm/tree/master/xorm) * [VeryHour](http://veryhour.com) -## 15.FAQ - -1.How the xorm tag use both with json? - - Use space. - -```Go -type User struct { - Name string `json:"name" xorm:"name"` -} +## 15.FAQ + +1.How the xorm tag use both with json? + + Use space. + +```Go +type User struct { + Name string `json:"name" xorm:"name"` +} ``` diff --git a/examples/cache.go b/examples/cache.go index 8fd8f4a8..c5d50273 100644 --- a/examples/cache.go +++ b/examples/cache.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/lunny/xorm" - "github.com/lunny/xorm/caches" + "github.com/go-xorm/xorm" + "github.com/go-xorm/xorm/caches" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/cachegoroutine.go b/examples/cachegoroutine.go index 117490d6..925a16ca 100644 --- a/examples/cachegoroutine.go +++ b/examples/cachegoroutine.go @@ -3,7 +3,7 @@ package main import ( "fmt" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" "os" ) diff --git a/examples/conversion.go b/examples/conversion.go index f16869c4..1a74dea8 100644 --- a/examples/conversion.go +++ b/examples/conversion.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/derive.go b/examples/derive.go index 826b4271..2a340060 100644 --- a/examples/derive.go +++ b/examples/derive.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/goroutine.go b/examples/goroutine.go index 6d45c924..b18fe4f8 100644 --- a/examples/goroutine.go +++ b/examples/goroutine.go @@ -6,7 +6,7 @@ import ( "runtime" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/maxconnect.go b/examples/maxconnect.go index e383de13..8ec82d2a 100644 --- a/examples/maxconnect.go +++ b/examples/maxconnect.go @@ -6,7 +6,7 @@ import ( "runtime" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/pool.go b/examples/pool.go index 746cdf8d..7511bb6c 100644 --- a/examples/pool.go +++ b/examples/pool.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/singlemapping.go b/examples/singlemapping.go index 6954d7ee..f2d675b8 100644 --- a/examples/singlemapping.go +++ b/examples/singlemapping.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/examples/sync.go b/examples/sync.go index 043bffa8..f26026aa 100644 --- a/examples/sync.go +++ b/examples/sync.go @@ -4,7 +4,7 @@ import ( "fmt" _ "github.com/bylevel/pq" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" ) diff --git a/xorm/.gopmfile b/xorm/.gopmfile index a77947be..6fcf08b9 100644 --- a/xorm/.gopmfile +++ b/xorm/.gopmfile @@ -1,2 +1,2 @@ [deps] -github.com/lunny/xorm=../ \ No newline at end of file +github.com/go-xorm/xorm=../ \ No newline at end of file diff --git a/xorm/README.md b/xorm/README.md index b0d39b86..f4dbc9e6 100644 --- a/xorm/README.md +++ b/xorm/README.md @@ -5,11 +5,11 @@ xorm tools is a set of tools for database operation. ## Install -`go get github.com/lunny/xorm/xorm` +`go get github.com/go-xorm/xorm/xorm` and you should install the depends below: -* github.com/lunny/xorm +* github.com/go-xorm/xorm * Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) diff --git a/xorm/c++.go b/xorm/c++.go index bbfdd3b1..f5a0907a 100644 --- a/xorm/c++.go +++ b/xorm/c++.go @@ -5,7 +5,7 @@ import ( "strings" "text/template" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" ) var ( diff --git a/xorm/go.go b/xorm/go.go index d599f074..382b5b18 100644 --- a/xorm/go.go +++ b/xorm/go.go @@ -8,7 +8,7 @@ import ( "strings" "text/template" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" ) var ( diff --git a/xorm/lang.go b/xorm/lang.go index a4785647..3af43feb 100644 --- a/xorm/lang.go +++ b/xorm/lang.go @@ -1,10 +1,10 @@ package main import ( + "github.com/go-xorm/core" "io/ioutil" "strings" "text/template" - "github.com/lunny/xorm/core" ) type LangTmpl struct { diff --git a/xorm/reverse.go b/xorm/reverse.go index 5bd5f33b..1db8f115 100644 --- a/xorm/reverse.go +++ b/xorm/reverse.go @@ -14,8 +14,8 @@ import ( _ "github.com/bylevel/pq" "github.com/dvirsky/go-pylog/logging" _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" - "github.com/lunny/xorm/core" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" _ "github.com/ziutek/mymysql/godrv" diff --git a/xorm/shell.go b/xorm/shell.go index 6fd0db6a..5258e4c4 100644 --- a/xorm/shell.go +++ b/xorm/shell.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/lunny/xorm" + "github.com/go-xorm/xorm" "strings" ) From f30dadfd0220b7724644599cb5373564bf8bc655 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 11 Apr 2014 17:22:21 +0800 Subject: [PATCH 37/41] move tests to a sereprated repository --- tests/base_test.go | 4185 ---------------------------------- tests/benchmark.bat | 1 - tests/benchmark.sh | 1 - tests/benchmark_base_test.go | 176 -- tests/mssql_test.go | 144 -- tests/mymysql_test.go | 169 -- tests/mysql_test.go | 222 -- tests/postgres_test.go | 202 -- tests/sqlite3_test.go | 183 -- tests/testdata/mysql_ddl.sql | 8 - 10 files changed, 5291 deletions(-) delete mode 100644 tests/base_test.go delete mode 100644 tests/benchmark.bat delete mode 100755 tests/benchmark.sh delete mode 100644 tests/benchmark_base_test.go delete mode 100644 tests/mssql_test.go delete mode 100644 tests/mymysql_test.go delete mode 100644 tests/mysql_test.go delete mode 100644 tests/postgres_test.go delete mode 100644 tests/sqlite3_test.go delete mode 100644 tests/testdata/mysql_ddl.sql diff --git a/tests/base_test.go b/tests/base_test.go deleted file mode 100644 index 4f5704a8..00000000 --- a/tests/base_test.go +++ /dev/null @@ -1,4185 +0,0 @@ -package tests - -import ( - "errors" - "fmt" - "strings" - "testing" - "time" - - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" -) - -/* -CREATE TABLE `userinfo` ( - `id` INT(10) NULL AUTO_INCREMENT, - `username` VARCHAR(64) NULL, - `departname` VARCHAR(64) NULL, - `created` DATE NULL, - PRIMARY KEY (`uid`) -); -CREATE TABLE `userdeatail` ( - `id` INT(10) NULL, - `intro` TEXT NULL, - `profile` TEXT NULL, - PRIMARY KEY (`uid`) -); -*/ - -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)"` -} - -func directCreateTable(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&Userinfo{}, &Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.Sync(&Userinfo{}, &Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.DropTables(&Userinfo{}, &Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&Userinfo{}, &Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateIndexes(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateIndexes(&Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateUniques(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateUniques(&Userdetail{}) - if err != nil { - t.Error(err) - panic(err) - } -} - -func insert(engine *xorm.Engine, t *testing.T) { - user := Userinfo{0, "xiaolunwen", "dev", "lunny", time.Now(), - Userdetail{Id: 1}, 1.78, []byte{1, 2, 3}, true} - cnt, err := engine.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) - return - } - if user.Uid <= 0 { - err = errors.New("not return id error") - t.Error(err) - panic(err) - } - - user.Uid = 0 - cnt, err = engine.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 testQuery(engine *xorm.Engine, t *testing.T) { - sql := "select * from userinfo" - results, err := engine.Query(sql) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(results) -} - -func exec(engine *xorm.Engine, t *testing.T) { - sql := "update userinfo set username=? where id=?" - res, err := engine.Exec(sql, "xiaolun", 1) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(res) -} - -func testQuerySameMapper(engine *xorm.Engine, t *testing.T) { - sql := "select * from `Userinfo`" - results, err := engine.Query(sql) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(results) -} - -func execSameMapper(engine *xorm.Engine, t *testing.T) { - sql := "update `Userinfo` set `Username`=? where (id)=?" - res, err := engine.Exec(sql, "xiaolun", 1) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(res) -} - -func insertAutoIncr(engine *xorm.Engine, t *testing.T) { - // 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 := engine.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) - return - } - if user.Uid <= 0 { - t.Error(errors.New("not return id error")) - } -} - -type BigInsert struct { -} - -func insertDefault(engine *xorm.Engine, t *testing.T) { - -} - -func insertMulti(engine *xorm.Engine, t *testing.T) { - //engine.InsertMany = true - 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 := engine.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 = engine.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) - return - } -} - -func insertTwoTable(engine *xorm.Engine, t *testing.T) { - 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 := engine.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) - return - } -} - -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)"` -} - -type Condi map[string]interface{} - -func update(engine *xorm.Engine, t *testing.T) { - // update by id - user := Userinfo{Username: "xxx", Height: 1.2} - cnt, err := engine.Id(4).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 = engine.Table(&user).Id(4).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 = engine.Update(&Userinfo{Username: "yyy"}, &user) - if err != nil { - t.Error(err) - panic(err) - } - total, err := engine.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 = engine.Sync(&Article{}) - if err != nil { - t.Error(err) - panic(err) - } - - defer func() { - err = engine.DropTables(&Article{}) - if err != nil { - t.Error(err) - panic(err) - } - }() - - a := &Article{0, "1", "2", "3", "4", "5", 2} - cnt, err = engine.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 = engine.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 - } - - type UpdateAllCols struct { - Id int64 - Bool bool - String string - } - - col1 := &UpdateAllCols{} - err = engine.Sync(col1) - if err != nil { - t.Error(err) - panic(err) - } - - _, err = engine.Insert(col1) - if err != nil { - t.Error(err) - panic(err) - } - - col2 := &UpdateAllCols{col1.Id, true, ""} - _, err = engine.Id(col2.Id).AllCols().Update(col2) - if err != nil { - t.Error(err) - panic(err) - } - - col3 := &UpdateAllCols{} - has, err := engine.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 - } - - { - type UpdateMustCols struct { - Id int64 - Bool bool - String string - } - - col1 := &UpdateMustCols{} - err = engine.Sync(col1) - if err != nil { - t.Error(err) - panic(err) - } - - _, err = engine.Insert(col1) - if err != nil { - t.Error(err) - panic(err) - } - - col2 := &UpdateMustCols{col1.Id, true, ""} - boolStr := engine.ColumnMapper.Obj2Table("Bool") - stringStr := engine.ColumnMapper.Obj2Table("String") - _, err = engine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2) - if err != nil { - t.Error(err) - panic(err) - } - - col3 := &UpdateMustCols{} - has, err := engine.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 - } - } -} - -func updateSameMapper(engine *xorm.Engine, t *testing.T) { - // update by id - user := Userinfo{Username: "xxx", Height: 1.2} - cnt, err := engine.Id(4).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 = engine.Table(&user).Id(4).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 = engine.Update(&Userinfo{Username: "yyy"}, &user) - if err != nil { - t.Error(err) - panic(err) - } - - total, err := engine.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 - } -} - -func testDelete(engine *xorm.Engine, t *testing.T) { - user := Userinfo{Uid: 1} - cnt, err := engine.Delete(&user) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("delete not returned 1") - t.Error(err) - panic(err) - return - } - - user.Uid = 0 - user.IsMan = true - has, err := engine.Id(3).Get(&user) - if err != nil { - t.Error(err) - panic(err) - } - - if has { - //var tt time.Time - //user.Created = tt - cnt, err := engine.UseBool().Delete(&user) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - t.Error(errors.New("delete failed")) - panic(err) - } - } -} - -type NoIdUser struct { - User string `xorm:"unique"` - Remain int64 - Total int64 -} - -func get(engine *xorm.Engine, t *testing.T) { - user := Userinfo{Uid: 2} - - has, err := engine.Get(&user) - if err != nil { - t.Error(err) - panic(err) - } - if has { - fmt.Println(user) - } else { - fmt.Println("no record id is 2") - } - - err = engine.Sync(&NoIdUser{}) - if err != nil { - t.Error(err) - panic(err) - } - - userCol := engine.ColumnMapper.Obj2Table("User") - - _, err = engine.Where("`"+userCol+"` = ?", "xlw").Delete(&NoIdUser{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&NoIdUser{"xlw", 20, 100}) - if err != nil { - t.Error(err) - panic(err) - } - - if cnt != 1 { - err = errors.New("insert not returned 1") - t.Error(err) - panic(err) - } - - noIdUser := new(NoIdUser) - has, err = engine.Where("`"+userCol+"` = ?", "xlw").Get(noIdUser) - if err != nil { - t.Error(err) - panic(err) - } - - if !has { - err = errors.New("get not returned 1") - t.Error(err) - panic(err) - } - fmt.Println(noIdUser) -} - -func cascadeGet(engine *xorm.Engine, t *testing.T) { - user := Userinfo{Uid: 11} - - has, err := engine.Get(&user) - if err != nil { - t.Error(err) - panic(err) - } - if has { - fmt.Println(user) - } else { - fmt.Println("no record id is 2") - } -} - -func find(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - - err := engine.Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - for _, user := range users { - fmt.Println(user) - } - - users2 := make([]Userinfo, 0) - userinfo := engine.TableMapper.Obj2Table("Userinfo") - err = engine.Sql("select * from " + engine.Quote(userinfo)).Find(&users2) - if err != nil { - t.Error(err) - panic(err) - } -} - -func find2(engine *xorm.Engine, t *testing.T) { - users := make([]*Userinfo, 0) - - err := engine.Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - for _, user := range users { - fmt.Println(user) - } -} - -func findMap(engine *xorm.Engine, t *testing.T) { - users := make(map[int64]Userinfo) - - err := engine.Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - for _, user := range users { - fmt.Println(user) - } -} - -func findMap2(engine *xorm.Engine, t *testing.T) { - users := make(map[int64]*Userinfo) - - err := engine.Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - for id, user := range users { - fmt.Println(id, user) - } -} - -func count(engine *xorm.Engine, t *testing.T) { - user := Userinfo{Departname: "dev"} - total, err := engine.Count(&user) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Printf("Total %d records!!!\n", total) -} - -func where(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.Where("(id) > ?", 2).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) - - err = engine.Where("(id) > ?", 2).And("(id) < ?", 10).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) -} - -func in(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.In("(id)", 7, 8, 9).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) - if len(users) != 3 { - err = errors.New("in uses should be 7,8,9 total 3") - t.Error(err) - panic(err) - } - - for _, user := range users { - if user.Uid != 7 && user.Uid != 8 && user.Uid != 9 { - err = errors.New("in uses should be 7,8,9 total 3") - t.Error(err) - panic(err) - } - } - - users = make([]Userinfo, 0) - ids := []interface{}{7, 8, 9} - department := engine.ColumnMapper.Obj2Table("Departname") - err = engine.Where("`"+department+"` = ?", "dev").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 7,8,9 total 3") - t.Error(err) - panic(err) - } - - for _, user := range users { - if user.Uid != 7 && user.Uid != 8 && user.Uid != 9 { - err = errors.New("in uses should be 7,8,9 total 3") - t.Error(err) - panic(err) - } - } - - dev := engine.ColumnMapper.Obj2Table("Dev") - - err = engine.In("(id)", 1).In("(id)", 2).In(department, dev).Find(&users) - - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) - - cnt, err := engine.In("(id)", 4).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 := engine.Id(4).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 = engine.In("(id)", 4).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 = engine.In("(id)", 5).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) - } -} - -func limit(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.Limit(2, 1).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) -} - -func order(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.OrderBy("id desc").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) - - users2 := make([]Userinfo, 0) - err = engine.Asc("id", "username").Desc("height").Find(&users2) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users2) -} - -func join(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.Join("LEFT", "userdetail", "userinfo.id=userdetail.id").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } -} - -func having(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.GroupBy("username").Having("username='xlw'").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) -} - -func orderSameMapper(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.OrderBy("(id) desc").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) - - users2 := make([]Userinfo, 0) - err = engine.Asc("(id)", "Username").Desc("Height").Find(&users2) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users2) -} - -func joinSameMapper(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.Join("LEFT", "`Userdetail`", "`Userinfo`.`(id)`=`Userdetail`.`Id`").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } -} - -func havingSameMapper(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - err := engine.GroupBy("Username").Having(`"Username"='xlw'`).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(users) -} - -func transaction(engine *xorm.Engine, t *testing.T) { - counter := func() { - total, err := engine.Count(&Userinfo{}) - if err != nil { - t.Error(err) - } - fmt.Printf("----now total %v records\n", total) - } - - counter() - defer counter() - session := engine.NewSession() - defer session.Close() - - err := session.Begin() - if err != nil { - t.Error(err) - panic(err) - } - //session.IsAutoRollback = false - 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) - } - - 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) - } - - err = session.Commit() - if err != nil { - t.Error(err) - panic(err) - } - // panic(err) !nashtsai! should remove this -} - -func combineTransaction(engine *xorm.Engine, t *testing.T) { - counter := func() { - total, err := engine.Count(&Userinfo{}) - if err != nil { - t.Error(err) - } - fmt.Printf("----now total %v records\n", total) - } - - counter() - defer counter() - session := engine.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 combineTransactionSameMapper(engine *xorm.Engine, t *testing.T) { - counter := func() { - total, err := engine.Count(&Userinfo{}) - if err != nil { - t.Error(err) - } - fmt.Printf("----now total %v records\n", total) - } - - counter() - defer counter() - session := engine.NewSession() - defer session.Close() - - err := session.Begin() - if err != nil { - t.Error(err) - panic(err) - } - //session.IsAutoRollback = false - 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 table(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables("user_user") - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.Table("user_user").CreateTable(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } -} - -func createMultiTables(engine *xorm.Engine, t *testing.T) { - session := engine.NewSession() - defer session.Close() - - user := &Userinfo{} - err := session.Begin() - if err != nil { - t.Error(err) - panic(err) - } - for i := 0; i < 10; i++ { - tableName := fmt.Sprintf("user_%v", i) - - err = session.DropTable(tableName) - if err != nil { - session.Rollback() - t.Error(err) - panic(err) - } - - err = session.Table(tableName).CreateTable(user) - if err != nil { - session.Rollback() - t.Error(err) - panic(err) - } - } - err = session.Commit() - if err != nil { - t.Error(err) - panic(err) - } -} - -func tableOp(engine *xorm.Engine, t *testing.T) { - user := Userinfo{Username: "tablexiao", Departname: "dev", Alias: "lunny", Created: time.Now()} - tableName := fmt.Sprintf("user_%v", len(user.Username)) - cnt, err := engine.Table(tableName).Insert(&user) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert not returned 1") - t.Error(err) - panic(err) - return - } - - has, err := engine.Table(tableName).Get(&Userinfo{Username: "tablexiao"}) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("Get has return false") - t.Error(err) - panic(err) - return - } - - users := make([]Userinfo, 0) - err = engine.Table(tableName).Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - - id := user.Uid - cnt, err = engine.Table(tableName).Id(id).Update(&Userinfo{Username: "tableda"}) - if err != nil { - t.Error(err) - panic(err) - } - - _, err = engine.Table(tableName).Id(id).Delete(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } -} - -func testCharst(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables("user_charset") - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.Charset("utf8").Table("user_charset").CreateTable(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } -} - -func testStoreEngine(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables("user_store_engine") - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.StoreEngine("InnoDB").Table("user_store_engine").CreateTable(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } -} - -type tempUser struct { - Id int64 - Username string -} - -func testCols(engine *xorm.Engine, t *testing.T) { - users := []Userinfo{} - err := engine.Cols("id, username").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - - fmt.Println(users) - - tmpUsers := []tempUser{} - err = engine.NoCache().Table("userinfo").Cols("id, username").Find(&tmpUsers) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(tmpUsers) - - user := &Userinfo{Uid: 1, Alias: "", Height: 0} - affected, err := engine.Cols("departname, height").Id(1).Update(user) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println("===================", user, affected) -} - -func testColsSameMapper(engine *xorm.Engine, t *testing.T) { - users := []Userinfo{} - err := engine.Cols("id, Username").Find(&users) - if err != nil { - t.Error(err) - panic(err) - } - - fmt.Println(users) - - tmpUsers := []tempUser{} - // TODO: should use cache - err = engine.NoCache().Table("Userinfo").Cols("id, Username").Find(&tmpUsers) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(tmpUsers) - - user := &Userinfo{Uid: 1, Alias: "", Height: 0} - affected, err := engine.Cols("Departname, Height").Update(user) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println("===================", user, affected) -} - -type tempUser2 struct { - tempUser `xorm:"extends"` - Departname string -} - -func testExtends(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&tempUser2{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&tempUser2{}) - if err != nil { - t.Error(err) - panic(err) - } - - tu := &tempUser2{tempUser{0, "extends"}, "dev depart"} - _, err = engine.Insert(tu) - if err != nil { - t.Error(err) - panic(err) - } - - tu2 := &tempUser2{} - _, err = engine.Get(tu2) - if err != nil { - t.Error(err) - panic(err) - } - - tu3 := &tempUser2{tempUser{0, "extends update"}, ""} - _, err = engine.Id(tu2.Id).Update(tu3) - if err != nil { - t.Error(err) - panic(err) - } -} - -type allCols struct { - Bit int `xorm:"BIT"` - TinyInt int8 `xorm:"TINYINT"` - SmallInt int16 `xorm:"SMALLINT"` - MediumInt int32 `xorm:"MEDIUMINT"` - Int int `xorm:"INT"` - Integer int `xorm:"INTEGER"` - BigInt int64 `xorm:"BIGINT"` - - Char string `xorm:"CHAR(12)"` - Varchar string `xorm:"VARCHAR(54)"` - TinyText string `xorm:"TINYTEXT"` - Text string `xorm:"TEXT"` - MediumText string `xorm:"MEDIUMTEXT"` - LongText string `xorm:"LONGTEXT"` - Binary []byte `xorm:"BINARY(23)"` - VarBinary []byte `xorm:"VARBINARY(12)"` - - Date time.Time `xorm:"DATE"` - DateTime time.Time `xorm:"DATETIME"` - Time time.Time `xorm:"TIME"` - TimeStamp time.Time `xorm:"TIMESTAMP"` - - Decimal float64 `xorm:"DECIMAL"` - Numeric float64 `xorm:"NUMERIC"` - - Real float32 `xorm:"REAL"` - Float float32 `xorm:"FLOAT"` - Double float64 `xorm:"DOUBLE"` - - TinyBlob []byte `xorm:"TINYBLOB"` - Blob []byte `xorm:"BLOB"` - MediumBlob []byte `xorm:"MEDIUMBLOB"` - LongBlob []byte `xorm:"LONGBLOB"` - Bytea []byte `xorm:"BYTEA"` - - Bool bool `xorm:"BOOL"` - - Serial int `xorm:"SERIAL"` - //BigSerial int64 `xorm:"BIGSERIAL"` -} - -func testColTypes(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&allCols{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&allCols{}) - if err != nil { - t.Error(err) - panic(err) - } - - ac := &allCols{ - 1, - 4, - 8, - 16, - 32, - 64, - 128, - - "123", - "fafdafa", - "fafafafdsafdsafdaf", - "fdsafafdsafdsaf", - "fafdsafdsafdsfadasfsfafd", - "fadfdsafdsafasfdasfds", - []byte("fdafsafdasfdsafsa"), - []byte("fdsafsdafs"), - - time.Now(), - time.Now(), - time.Now(), - time.Now(), - - 1.34, - 2.44302346, - - 1.3344, - 2.59693523, - 3.2342523543, - - []byte("fafdasf"), - []byte("fafdfdsafdsafasf"), - []byte("faffadsfdsdasf"), - []byte("faffdasfdsadasf"), - []byte("fafasdfsadffdasf"), - - true, - - 0, - //21, - } - - cnt, err := engine.Insert(ac) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert return not 1") - t.Error(err) - panic(err) - } - newAc := &allCols{} - has, err := engine.Get(newAc) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("error no ideas") - t.Error(err) - panic(err) - } - - // don't use this type as query condition - newAc.Real = 0 - newAc.Float = 0 - newAc.Double = 0 - newAc.LongText = "" - newAc.TinyText = "" - newAc.MediumText = "" - newAc.Text = "" - cnt, err = engine.Delete(newAc) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New(fmt.Sprintf("delete error, deleted counts is %v", cnt)) - t.Error(err) - panic(err) - } -} - -type MyInt int -type MyUInt uint -type MyFloat float64 -type MyString string - -/*func (s *MyString) FromDB(data []byte) error { - reflect. - s MyString(data) - return nil -} - -func (s *MyString) ToDB() ([]byte, error) { - return []byte(string(*s)), nil -}*/ - -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 testCustomType(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&MyStruct{}) - if err != nil { - t.Error(err) - panic(err) - return - } - - err = engine.CreateTables(&MyStruct{}) - 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 := engine.Insert(&i) - if err != nil { - t.Error(err) - panic(err) - return - } - if cnt != 1 { - err = errors.New("insert not returned 1") - t.Error(err) - panic(err) - return - } - - fmt.Println(i) - i.NameArray = []string{} - i.MSS = map[string]string{} - i.F = 0 - has, err := engine.Get(&i) - if err != nil { - t.Error(err) - panic(err) - } else if !has { - t.Error(errors.New("should get one record")) - panic(err) - } - - ss := []MyStruct{} - err = engine.Find(&ss) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(ss) - - sss := MyStruct{} - has, err = engine.Get(&sss) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(sss) - - if has { - sss.NameArray = []string{} - sss.MSS = map[string]string{} - cnt, err := engine.Delete(&sss) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - t.Error(errors.New("delete error")) - panic(err) - } - } -} - -type UserCU struct { - Id int64 - Name string - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -func testCreatedAndUpdated(engine *xorm.Engine, t *testing.T) { - u := new(UserCU) - err := engine.DropTables(u) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(u) - if err != nil { - t.Error(err) - panic(err) - } - - u.Name = "sss" - cnt, err := engine.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 = engine.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 = engine.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 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(engine *xorm.Engine, t *testing.T) { - err := engine.CreateTables(&IndexOrUnique{}) - if err != nil { - t.Error(err) - //panic(err) - } - - err = engine.DropTables(&IndexOrUnique{}) - if err != nil { - t.Error(err) - //panic(err) - } - - err = engine.CreateTables(&IndexOrUnique{}) - if err != nil { - t.Error(err) - //panic(err) - } - - err = engine.CreateIndexes(&IndexOrUnique{}) - if err != nil { - t.Error(err) - //panic(err) - } - - err = engine.CreateUniques(&IndexOrUnique{}) - if err != nil { - t.Error(err) - //panic(err) - } -} - -type IntId struct { - Id int `xorm:"pk autoincr"` - Name string -} - -type Int32Id struct { - Id int32 `xorm:"pk autoincr"` - Name string -} - -type UintId struct { - Id uint `xorm:"pk autoincr"` - Name string -} - -type Uint32Id struct { - Id uint32 `xorm:"pk autoincr"` - Name string -} - -type Uint64Id struct { - Id uint64 `xorm:"pk autoincr"` - Name string -} - -type StringPK struct { - Id string `xorm:"pk notnull"` - Name string -} - -func testIntId(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&IntId{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&IntId{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&IntId{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(IntId) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]IntId, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&IntId{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testInt32Id(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&Int32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&Int32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&Int32Id{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(Int32Id) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]Int32Id, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&Int32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testUintId(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&UintId{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&UintId{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&UintId{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(UintId) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]UintId, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&UintId{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testUint32Id(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&Uint32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&Uint32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&Uint32Id{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(Uint32Id) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]Uint32Id, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&Uint32Id{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testUint64Id(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&Uint64Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&Uint64Id{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&Uint64Id{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(Uint64Id) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]Uint64Id, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&Uint64Id{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testStringPK(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&StringPK{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&StringPK{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&StringPK{Name: "test"}) - if err != nil { - t.Error(err) - panic(err) - } - - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } - - bean := new(StringPK) - has, err := engine.Get(bean) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - beans := make([]StringPK, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - panic(err) - } - if len(beans) != 1 { - err = errors.New("get count should be one") - t.Error(err) - panic(err) - } - - cnt, err = engine.Id(bean.Id).Delete(&StringPK{}) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert count should be one") - t.Error(err) - panic(err) - } -} - -func testMetaInfo(engine *xorm.Engine, t *testing.T) { - tables, err := engine.DBMetas() - if err != nil { - t.Error(err) - panic(err) - } - - for _, table := range tables { - fmt.Println(table.Name) - //for _, col := range table.Columns() { - //TODO: engine.dialect show exported - //fmt.Println(col.String(engine.dia)) - //} - - for _, index := range table.Indexes { - fmt.Println(index.Name, index.Type, strings.Join(index.Cols, ",")) - } - } -} - -func testIterate(engine *xorm.Engine, t *testing.T) { - err := engine.Omit("is_man").Iterate(new(Userinfo), func(idx int, bean interface{}) error { - user := bean.(*Userinfo) - fmt.Println(idx, "--", user) - return nil - }) - - if err != nil { - t.Error(err) - panic(err) - } -} - -func testRows(engine *xorm.Engine, t *testing.T) { - rows, err := engine.Omit("is_man").Rows(new(Userinfo)) - if err != nil { - t.Error(err) - panic(err) - } - defer rows.Close() - - idx := 0 - user := new(Userinfo) - for rows.Next() { - err = rows.Scan(user) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(idx, "--", user) - idx++ - } -} - -type StrangeName struct { - Id_t int64 `xorm:"pk autoincr"` - Name string -} - -func testStrangeName(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(new(StrangeName)) - if err != nil { - t.Error(err) - } - - err = engine.CreateTables(new(StrangeName)) - if err != nil { - t.Error(err) - } - - _, err = engine.Insert(&StrangeName{Name: "sfsfdsfds"}) - if err != nil { - t.Error(err) - } - - beans := make([]StrangeName, 0) - err = engine.Find(&beans) - if err != nil { - t.Error(err) - } -} - -type VersionS struct { - Id int64 - Name string - Ver int `xorm:"version"` -} - -func testVersion(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(new(VersionS)) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(new(VersionS)) - if err != nil { - t.Error(err) - panic(err) - } - - ver := &VersionS{Name: "sfsfdsfds"} - _, err = engine.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 := engine.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 = engine.Id(ver.Id).Update(newVer) - if err != nil { - t.Error(err) - panic(err) - } - - newVer = new(VersionS) - has, err = engine.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) - } - - /* - newVer.Name = "-------" - _, err = engine.Id(ver.Id).Update(newVer) - if err != nil { - t.Error(err) - return - }*/ -} - -func testDistinct(engine *xorm.Engine, t *testing.T) { - users := make([]Userinfo, 0) - departname := engine.TableMapper.Obj2Table("Departname") - err := engine.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 = engine.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 testUseBool(engine *xorm.Engine, t *testing.T) { - cnt1, err := engine.Count(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } - - users := make([]Userinfo, 0) - err = engine.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 := engine.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 = engine.Update(&Userinfo{IsMan: true}) - if err == nil { - err = errors.New("error condition") - t.Error(err) - panic(err) - } -} - -func testBool(engine *xorm.Engine, t *testing.T) { - _, err := engine.UseBool().Update(&Userinfo{IsMan: true}) - if err != nil { - t.Error(err) - panic(err) - } - users := make([]Userinfo, 0) - err = engine.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 = engine.UseBool().Update(&Userinfo{IsMan: false}) - if err != nil { - t.Error(err) - panic(err) - } - users = make([]Userinfo, 0) - err = engine.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) - } - } -} - -type TTime struct { - Id int64 - T time.Time - Tz time.Time `xorm:"timestampz"` -} - -func testTime(engine *xorm.Engine, t *testing.T) { - err := engine.Sync(&TTime{}) - if err != nil { - t.Error(err) - panic(err) - } - - tt := &TTime{} - _, err = engine.Insert(tt) - if err != nil { - t.Error(err) - panic(err) - } - - tt2 := &TTime{Id: tt.Id} - has, err := engine.Get(tt2) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - err = errors.New("no record error") - t.Error(err) - panic(err) - } - - tt3 := &TTime{T: time.Now(), Tz: time.Now()} - _, err = engine.Insert(tt3) - if err != nil { - t.Error(err) - panic(err) - } - - tt4s := make([]TTime, 0) - err = engine.Find(&tt4s) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println("=======\n", tt4s, "=======\n") -} - -func testPrefixTableName(engine *xorm.Engine, t *testing.T) { - tempEngine, err := xorm.NewEngine(engine.DriverName, engine.DataSourceName) - if err != nil { - t.Error(err) - panic(err) - } - tempEngine.ShowSQL = true - mapper := core.NewPrefixMapper(core.SnakeMapper{}, "xlw_") - //tempEngine.SetMapper(mapper) - tempEngine.SetTableMapper(mapper) - exist, err := tempEngine.IsTableExist(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } - if exist { - err = tempEngine.DropTables(&Userinfo{}) - if err != nil { - t.Error(err) - panic(err) - } - } - err = tempEngine.CreateTables(&Userinfo{}) - if err != nil { - t.Error(err) - panic(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(engine *xorm.Engine, t *testing.T) { - err := engine.Sync(&CreatedUpdated{}) - if err != nil { - t.Error(err) - panic(err) - } - - c := &CreatedUpdated{Name: "test"} - _, err = engine.Insert(c) - if err != nil { - t.Error(err) - panic(err) - } - - c2 := new(CreatedUpdated) - has, err := engine.Id(c.Id).Get(c2) - if err != nil { - t.Error(err) - panic(err) - } - - if !has { - panic(errors.New("no id")) - } - - c2.Value -= 1 - _, err = engine.Id(c2.Id).Update(c2) - if err != nil { - t.Error(err) - panic(err) - } -} - -type ProcessorsStruct struct { - Id int64 - - B4InsertFlag int - AfterInsertedFlag int - B4UpdateFlag int - AfterUpdatedFlag int - B4DeleteFlag int `xorm:"-"` - AfterDeletedFlag int `xorm:"-"` - - B4InsertViaExt int - AfterInsertedViaExt int - B4UpdateViaExt int - AfterUpdatedViaExt int - B4DeleteViaExt int `xorm:"-"` - AfterDeletedViaExt 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) AfterInsert() { - p.AfterInsertedFlag = 1 -} - -func (p *ProcessorsStruct) AfterUpdate() { - p.AfterUpdatedFlag = 1 -} - -func (p *ProcessorsStruct) AfterDelete() { - p.AfterDeletedFlag = 1 -} - -func testProcessors(engine *xorm.Engine, t *testing.T) { - // tempEngine, err := NewEngine(engine.DriverName, engine.DataSourceName) - // if err != nil { - // t.Error(err) - // panic(err) - // } - - engine.ShowSQL = true - err := engine.DropTables(&ProcessorsStruct{}) - if err != nil { - t.Error(err) - panic(err) - } - p := &ProcessorsStruct{} - - err = engine.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 = engine.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 = engine.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")) - } - } - // -- - - // 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 = engine.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 = engine.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))) - } - } - // -- - - // 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 = engine.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 := engine.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 = engine.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")) - } - } - } - // -- -} - -func testProcessorsTx(engine *xorm.Engine, t *testing.T) { - // tempEngine, err := NewEngine(engine.DriverName, engine.DataSourceName) - // if err != nil { - // t.Error(err) - // panic(err) - // } - - // tempEngine.ShowSQL = true - err := engine.DropTables(&ProcessorsStruct{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&ProcessorsStruct{}) - if err != nil { - t.Error(err) - panic(err) - } - - // test insert processors with tx rollback - session := engine.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 = engine.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 = engine.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 = engine.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 = engine.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 = engine.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 commit - session = engine.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 = engine.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 = engine.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 = engine.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 = engine.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() - // -- -} - -type NullData struct { - Id int64 - StringPtr *string - StringPtr2 *string `xorm:"text"` - BoolPtr *bool - BytePtr *byte - UintPtr *uint - Uint8Ptr *uint8 - Uint16Ptr *uint16 - Uint32Ptr *uint32 - Uint64Ptr *uint64 - IntPtr *int - Int8Ptr *int8 - Int16Ptr *int16 - Int32Ptr *int32 - Int64Ptr *int64 - RunePtr *rune - Float32Ptr *float32 - Float64Ptr *float64 - // Complex64Ptr *complex64 // !nashtsai! XORM yet support complex128: 'json: unsupported type: complex128' - // Complex128Ptr *complex128 // !nashtsai! XORM yet support complex128: 'json: unsupported type: complex128' - TimePtr *time.Time -} - -type NullData2 struct { - Id int64 - StringPtr string - StringPtr2 string `xorm:"text"` - BoolPtr bool - BytePtr byte - UintPtr uint - Uint8Ptr uint8 - Uint16Ptr uint16 - Uint32Ptr uint32 - Uint64Ptr uint64 - IntPtr int - Int8Ptr int8 - Int16Ptr int16 - Int32Ptr int32 - Int64Ptr int64 - RunePtr rune - Float32Ptr float32 - Float64Ptr float64 - // Complex64Ptr complex64 // !nashtsai! XORM yet support complex128: 'json: unsupported type: complex128' - // Complex128Ptr complex128 // !nashtsai! XORM yet support complex128: 'json: unsupported type: complex128' - TimePtr time.Time -} - -type NullData3 struct { - Id int64 - StringPtr *string -} - -func testPointerData(engine *xorm.Engine, t *testing.T) { - - err := engine.DropTables(&NullData{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&NullData{}) - if err != nil { - t.Error(err) - panic(err) - } - - nullData := NullData{ - StringPtr: new(string), - StringPtr2: new(string), - BoolPtr: new(bool), - BytePtr: new(byte), - UintPtr: new(uint), - Uint8Ptr: new(uint8), - Uint16Ptr: new(uint16), - Uint32Ptr: new(uint32), - Uint64Ptr: new(uint64), - IntPtr: new(int), - Int8Ptr: new(int8), - Int16Ptr: new(int16), - Int32Ptr: new(int32), - Int64Ptr: new(int64), - RunePtr: new(rune), - Float32Ptr: new(float32), - Float64Ptr: new(float64), - // Complex64Ptr: new(complex64), - // Complex128Ptr: new(complex128), - TimePtr: new(time.Time), - } - - *nullData.StringPtr = "abc" - *nullData.StringPtr2 = "123" - *nullData.BoolPtr = true - *nullData.BytePtr = 1 - *nullData.UintPtr = 1 - *nullData.Uint8Ptr = 1 - *nullData.Uint16Ptr = 1 - *nullData.Uint32Ptr = 1 - *nullData.Uint64Ptr = 1 - *nullData.IntPtr = -1 - *nullData.Int8Ptr = -1 - *nullData.Int16Ptr = -1 - *nullData.Int32Ptr = -1 - *nullData.Int64Ptr = -1 - *nullData.RunePtr = 1 - *nullData.Float32Ptr = -1.2 - *nullData.Float64Ptr = -1.1 - // *nullData.Complex64Ptr = 123456789012345678901234567890 - // *nullData.Complex128Ptr = 123456789012345678901234567890123456789012345678901234567890 - *nullData.TimePtr = time.Now() - - cnt, err := engine.Insert(&nullData) - fmt.Println(nullData.Id) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert not returned 1") - t.Error(err) - panic(err) - return - } - if nullData.Id <= 0 { - err = errors.New("not return id error") - t.Error(err) - panic(err) - } - - // verify get values - nullDataGet := NullData{} - has, err := engine.Id(nullData.Id).Get(&nullDataGet) - if err != nil { - t.Error(err) - panic(err) - } else if !has { - t.Error(errors.New("ID not found")) - } - - if *nullDataGet.StringPtr != *nullData.StringPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr))) - } - - if *nullDataGet.StringPtr2 != *nullData.StringPtr2 { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr2))) - } - - if *nullDataGet.BoolPtr != *nullData.BoolPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%t]", *nullDataGet.BoolPtr))) - } - - if *nullDataGet.UintPtr != *nullData.UintPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.UintPtr))) - } - - if *nullDataGet.Uint8Ptr != *nullData.Uint8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint8Ptr))) - } - - if *nullDataGet.Uint16Ptr != *nullData.Uint16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint16Ptr))) - } - - if *nullDataGet.Uint32Ptr != *nullData.Uint32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint32Ptr))) - } - - if *nullDataGet.Uint64Ptr != *nullData.Uint64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint64Ptr))) - } - - if *nullDataGet.IntPtr != *nullData.IntPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.IntPtr))) - } - - if *nullDataGet.Int8Ptr != *nullData.Int8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int8Ptr))) - } - - if *nullDataGet.Int16Ptr != *nullData.Int16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int16Ptr))) - } - - if *nullDataGet.Int32Ptr != *nullData.Int32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int32Ptr))) - } - - if *nullDataGet.Int64Ptr != *nullData.Int64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int64Ptr))) - } - - if *nullDataGet.RunePtr != *nullData.RunePtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.RunePtr))) - } - - if *nullDataGet.Float32Ptr != *nullData.Float32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float32Ptr))) - } - - if *nullDataGet.Float64Ptr != *nullData.Float64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float64Ptr))) - } - - // if *nullDataGet.Complex64Ptr != *nullData.Complex64Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex64Ptr))) - // } - - // if *nullDataGet.Complex128Ptr != *nullData.Complex128Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex128Ptr))) - // } - - /*if (*nullDataGet.TimePtr).Unix() != (*nullData.TimePtr).Unix() { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]:[%v]", *nullDataGet.TimePtr, *nullData.TimePtr))) - } else { - // !nashtsai! mymysql driver will failed this test case, due the time is roundup to nearest second, I would considered this is a bug in mymysql driver - fmt.Printf("time value: [%v]:[%v]", *nullDataGet.TimePtr, *nullData.TimePtr) - fmt.Println() - }*/ - // -- - - // using instance type should just work too - nullData2Get := NullData2{} - - tableName := engine.TableMapper.Obj2Table("NullData") - - has, err = engine.Table(tableName).Id(nullData.Id).Get(&nullData2Get) - if err != nil { - t.Error(err) - panic(err) - } else if !has { - t.Error(errors.New("ID not found")) - } - - if nullData2Get.StringPtr != *nullData.StringPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.StringPtr))) - } - - if nullData2Get.StringPtr2 != *nullData.StringPtr2 { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.StringPtr2))) - } - - if nullData2Get.BoolPtr != *nullData.BoolPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%t]", nullData2Get.BoolPtr))) - } - - if nullData2Get.UintPtr != *nullData.UintPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.UintPtr))) - } - - if nullData2Get.Uint8Ptr != *nullData.Uint8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Uint8Ptr))) - } - - if nullData2Get.Uint16Ptr != *nullData.Uint16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Uint16Ptr))) - } - - if nullData2Get.Uint32Ptr != *nullData.Uint32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Uint32Ptr))) - } - - if nullData2Get.Uint64Ptr != *nullData.Uint64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Uint64Ptr))) - } - - if nullData2Get.IntPtr != *nullData.IntPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.IntPtr))) - } - - if nullData2Get.Int8Ptr != *nullData.Int8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Int8Ptr))) - } - - if nullData2Get.Int16Ptr != *nullData.Int16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Int16Ptr))) - } - - if nullData2Get.Int32Ptr != *nullData.Int32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Int32Ptr))) - } - - if nullData2Get.Int64Ptr != *nullData.Int64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Int64Ptr))) - } - - if nullData2Get.RunePtr != *nullData.RunePtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.RunePtr))) - } - - if nullData2Get.Float32Ptr != *nullData.Float32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Float32Ptr))) - } - - if nullData2Get.Float64Ptr != *nullData.Float64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Float64Ptr))) - } - - // if nullData2Get.Complex64Ptr != *nullData.Complex64Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Complex64Ptr))) - // } - - // if nullData2Get.Complex128Ptr != *nullData.Complex128Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", nullData2Get.Complex128Ptr))) - // } - - /*if nullData2Get.TimePtr.Unix() != (*nullData.TimePtr).Unix() { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]:[%v]", nullData2Get.TimePtr, *nullData.TimePtr))) - } else { - // !nashtsai! mymysql driver will failed this test case, due the time is roundup to nearest second, I would considered this is a bug in mymysql driver - fmt.Printf("time value: [%v]:[%v]", nullData2Get.TimePtr, *nullData.TimePtr) - fmt.Println() - }*/ - // -- -} - -func testNullValue(engine *xorm.Engine, t *testing.T) { - - err := engine.DropTables(&NullData{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&NullData{}) - if err != nil { - t.Error(err) - panic(err) - } - - nullData := NullData{} - - cnt, err := engine.Insert(&nullData) - fmt.Println(nullData.Id) - if err != nil { - t.Error(err) - panic(err) - } - if cnt != 1 { - err = errors.New("insert not returned 1") - t.Error(err) - panic(err) - return - } - if nullData.Id <= 0 { - err = errors.New("not return id error") - t.Error(err) - panic(err) - } - - nullDataGet := NullData{} - - has, err := engine.Id(nullData.Id).Get(&nullDataGet) - if err != nil { - t.Error(err) - panic(err) - } else if !has { - t.Error(errors.New("ID not found")) - } - - if nullDataGet.StringPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr))) - } - - if nullDataGet.StringPtr2 != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr2))) - } - - if nullDataGet.BoolPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%t]", *nullDataGet.BoolPtr))) - } - - if nullDataGet.UintPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.UintPtr))) - } - - if nullDataGet.Uint8Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint8Ptr))) - } - - if nullDataGet.Uint16Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint16Ptr))) - } - - if nullDataGet.Uint32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint32Ptr))) - } - - if nullDataGet.Uint64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint64Ptr))) - } - - if nullDataGet.IntPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.IntPtr))) - } - - if nullDataGet.Int8Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int8Ptr))) - } - - if nullDataGet.Int16Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int16Ptr))) - } - - if nullDataGet.Int32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int32Ptr))) - } - - if nullDataGet.Int64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int64Ptr))) - } - - if nullDataGet.RunePtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.RunePtr))) - } - - if nullDataGet.Float32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float32Ptr))) - } - - if nullDataGet.Float64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) - } - - // if nullDataGet.Complex64Ptr != nil { - // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Complex64Ptr))) - // } - - // if nullDataGet.Complex128Ptr != nil { - // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Complex128Ptr))) - // } - - if nullDataGet.TimePtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.TimePtr))) - } - - nullDataUpdate := NullData{ - StringPtr: new(string), - StringPtr2: new(string), - BoolPtr: new(bool), - BytePtr: new(byte), - UintPtr: new(uint), - Uint8Ptr: new(uint8), - Uint16Ptr: new(uint16), - Uint32Ptr: new(uint32), - Uint64Ptr: new(uint64), - IntPtr: new(int), - Int8Ptr: new(int8), - Int16Ptr: new(int16), - Int32Ptr: new(int32), - Int64Ptr: new(int64), - RunePtr: new(rune), - Float32Ptr: new(float32), - Float64Ptr: new(float64), - // Complex64Ptr: new(complex64), - // Complex128Ptr: new(complex128), - TimePtr: new(time.Time), - } - - *nullDataUpdate.StringPtr = "abc" - *nullDataUpdate.StringPtr2 = "123" - *nullDataUpdate.BoolPtr = true - *nullDataUpdate.BytePtr = 1 - *nullDataUpdate.UintPtr = 1 - *nullDataUpdate.Uint8Ptr = 1 - *nullDataUpdate.Uint16Ptr = 1 - *nullDataUpdate.Uint32Ptr = 1 - *nullDataUpdate.Uint64Ptr = 1 - *nullDataUpdate.IntPtr = -1 - *nullDataUpdate.Int8Ptr = -1 - *nullDataUpdate.Int16Ptr = -1 - *nullDataUpdate.Int32Ptr = -1 - *nullDataUpdate.Int64Ptr = -1 - *nullDataUpdate.RunePtr = 1 - *nullDataUpdate.Float32Ptr = -1.2 - *nullDataUpdate.Float64Ptr = -1.1 - // *nullDataUpdate.Complex64Ptr = 123456789012345678901234567890 - // *nullDataUpdate.Complex128Ptr = 123456789012345678901234567890123456789012345678901234567890 - *nullDataUpdate.TimePtr = time.Now() - - cnt, err = engine.Id(nullData.Id).Update(&nullDataUpdate) - if err != nil { - t.Error(err) - panic(err) - } else if cnt != 1 { - t.Error(errors.New("update count == 0, how can this happen!?")) - return - } - - // verify get values - nullDataGet = NullData{} - has, err = engine.Id(nullData.Id).Get(&nullDataGet) - if err != nil { - t.Error(err) - return - } else if !has { - t.Error(errors.New("ID not found")) - return - } - - if *nullDataGet.StringPtr != *nullDataUpdate.StringPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr))) - } - - if *nullDataGet.StringPtr2 != *nullDataUpdate.StringPtr2 { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr2))) - } - - if *nullDataGet.BoolPtr != *nullDataUpdate.BoolPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%t]", *nullDataGet.BoolPtr))) - } - - if *nullDataGet.UintPtr != *nullDataUpdate.UintPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.UintPtr))) - } - - if *nullDataGet.Uint8Ptr != *nullDataUpdate.Uint8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint8Ptr))) - } - - if *nullDataGet.Uint16Ptr != *nullDataUpdate.Uint16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint16Ptr))) - } - - if *nullDataGet.Uint32Ptr != *nullDataUpdate.Uint32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint32Ptr))) - } - - if *nullDataGet.Uint64Ptr != *nullDataUpdate.Uint64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint64Ptr))) - } - - if *nullDataGet.IntPtr != *nullDataUpdate.IntPtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.IntPtr))) - } - - if *nullDataGet.Int8Ptr != *nullDataUpdate.Int8Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int8Ptr))) - } - - if *nullDataGet.Int16Ptr != *nullDataUpdate.Int16Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int16Ptr))) - } - - if *nullDataGet.Int32Ptr != *nullDataUpdate.Int32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int32Ptr))) - } - - if *nullDataGet.Int64Ptr != *nullDataUpdate.Int64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int64Ptr))) - } - - if *nullDataGet.RunePtr != *nullDataUpdate.RunePtr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.RunePtr))) - } - - if *nullDataGet.Float32Ptr != *nullDataUpdate.Float32Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float32Ptr))) - } - - if *nullDataGet.Float64Ptr != *nullDataUpdate.Float64Ptr { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float64Ptr))) - } - - // if *nullDataGet.Complex64Ptr != *nullDataUpdate.Complex64Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex64Ptr))) - // } - - // if *nullDataGet.Complex128Ptr != *nullDataUpdate.Complex128Ptr { - // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex128Ptr))) - // } - - // !nashtsai! skipped mymysql test due to driver will round up time caused inaccuracy comparison - // skipped postgres test due to postgres driver doesn't read time.Time's timzezone info when stored in the db - // mysql and sqlite3 seem have done this correctly by storing datatime in UTC timezone, I think postgres driver - // prefer using timestamp with timezone to sovle the issue - if engine.DriverName != core.POSTGRES && engine.DriverName != "mymysql" && - engine.DriverName != core.MYSQL { - if (*nullDataGet.TimePtr).Unix() != (*nullDataUpdate.TimePtr).Unix() { - t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]:[%v]", *nullDataGet.TimePtr, *nullDataUpdate.TimePtr))) - } else { - // !nashtsai! mymysql driver will failed this test case, due the time is roundup to nearest second, I would considered this is a bug in mymysql driver - // inserted value unmatch: [2013-12-25 12:12:45 +0800 CST]:[2013-12-25 12:12:44.878903653 +0800 CST] - fmt.Printf("time value: [%v]:[%v]", *nullDataGet.TimePtr, *nullDataUpdate.TimePtr) - fmt.Println() - } - } - - // update to null values - nullDataUpdate = NullData{} - - string_ptr := engine.ColumnMapper.Obj2Table("StringPtr") - - cnt, err = engine.Id(nullData.Id).Cols(string_ptr).Update(&nullDataUpdate) - if err != nil { - t.Error(err) - panic(err) - } else if cnt != 1 { - t.Error(errors.New("update count == 0, how can this happen!?")) - return - } - - // verify get values - nullDataGet = NullData{} - has, err = engine.Id(nullData.Id).Get(&nullDataGet) - if err != nil { - t.Error(err) - return - } else if !has { - t.Error(errors.New("ID not found")) - return - } - - fmt.Printf("%+v", nullDataGet) - fmt.Println() - - if nullDataGet.StringPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr))) - } - /* - if nullDataGet.StringPtr2 != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr2))) - } - - if nullDataGet.BoolPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%t]", *nullDataGet.BoolPtr))) - } - - if nullDataGet.UintPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.UintPtr))) - } - - if nullDataGet.Uint8Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint8Ptr))) - } - - if nullDataGet.Uint16Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint16Ptr))) - } - - if nullDataGet.Uint32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint32Ptr))) - } - - if nullDataGet.Uint64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint64Ptr))) - } - - if nullDataGet.IntPtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.IntPtr))) - } - - if nullDataGet.Int8Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int8Ptr))) - } - - if nullDataGet.Int16Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int16Ptr))) - } - - if nullDataGet.Int32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int32Ptr))) - } - - if nullDataGet.Int64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int64Ptr))) - } - - if nullDataGet.RunePtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.RunePtr))) - } - - if nullDataGet.Float32Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float32Ptr))) - } - - if nullDataGet.Float64Ptr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) - } - - // if nullDataGet.Complex64Ptr != nil { - // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) - // } - - // if nullDataGet.Complex128Ptr != nil { - // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) - // } - - if nullDataGet.TimePtr != nil { - t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.TimePtr))) - }*/ - // -- - -} - -type CompositeKey struct { - Id1 int64 `xorm:"id1 pk"` - Id2 int64 `xorm:"id2 pk"` - UpdateStr string -} - -func testCompositeKey(engine *xorm.Engine, t *testing.T) { - - err := engine.DropTables(&CompositeKey{}) - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&CompositeKey{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&CompositeKey{11, 22, ""}) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("failed to insert CompositeKey{11, 22}")) - } - - cnt, err = engine.Insert(&CompositeKey{11, 22, ""}) - if err == nil || cnt == 1 { - t.Error(errors.New("inserted CompositeKey{11, 22}")) - } - - var compositeKeyVal CompositeKey - has, err := engine.Id(core.PK{11, 22}).Get(&compositeKeyVal) - if err != nil { - t.Error(err) - } else if !has { - t.Error(errors.New("can't get CompositeKey{11, 22}")) - } - - // test passing PK ptr, this test seem failed withCache - has, err = engine.Id(&core.PK{11, 22}).Get(&compositeKeyVal) - if err != nil { - t.Error(err) - } else if !has { - t.Error(errors.New("can't get CompositeKey{11, 22}")) - } - - compositeKeyVal = CompositeKey{UpdateStr: "test1"} - cnt, err = engine.Id(core.PK{11, 22}).Update(&compositeKeyVal) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("can't update CompositeKey{11, 22}")) - } - - cnt, err = engine.Id(core.PK{11, 22}).Delete(&CompositeKey{}) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("can't delete CompositeKey{11, 22}")) - } -} - -type Lowercase struct { - Id int64 - Name string - ended int64 `xorm:"-"` -} - -func testLowerCase(engine *xorm.Engine, t *testing.T) { - err := engine.Sync(&Lowercase{}) - _, err = engine.Where("(id) > 0").Delete(&Lowercase{}) - if err != nil { - t.Error(err) - panic(err) - } - _, err = engine.Insert(&Lowercase{ended: 1}) - if err != nil { - t.Error(err) - panic(err) - } - - ls := make([]Lowercase, 0) - err = engine.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) - } -} - -type User struct { - UserId string `xorm:"varchar(19) not null pk"` - NickName string `xorm:"varchar(19) not null"` - GameId uint32 `xorm:"integer pk"` - Score int32 `xorm:"integer"` -} - -func testCompositeKey2(engine *xorm.Engine, t *testing.T) { - err := engine.DropTables(&User{}) - - if err != nil { - t.Error(err) - panic(err) - } - - err = engine.CreateTables(&User{}) - if err != nil { - t.Error(err) - panic(err) - } - - cnt, err := engine.Insert(&User{"11", "nick", 22, 5}) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("failed to insert User{11, 22}")) - } - - cnt, err = engine.Insert(&User{"11", "nick", 22, 6}) - if err == nil || cnt == 1 { - t.Error(errors.New("inserted User{11, 22}")) - } - - var user User - has, err := engine.Id(core.PK{"11", 22}).Get(&user) - if err != nil { - t.Error(err) - } else if !has { - t.Error(errors.New("can't get User{11, 22}")) - } - - // test passing PK ptr, this test seem failed withCache - has, err = engine.Id(&core.PK{"11", 22}).Get(&user) - if err != nil { - t.Error(err) - } else if !has { - t.Error(errors.New("can't get User{11, 22}")) - } - - user = User{NickName: "test1"} - cnt, err = engine.Id(core.PK{"11", 22}).Update(&user) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("can't update User{11, 22}")) - } - - cnt, err = engine.Id(core.PK{"11", 22}).Delete(&User{}) - if err != nil { - t.Error(err) - } else if cnt != 1 { - t.Error(errors.New("can't delete CompositeKey{11, 22}")) - } -} - -type CustomTableName struct { - Id int64 - Name string -} - -func (c *CustomTableName) TableName() string { - return "customtablename" -} - -func testCustomTableName(engine *xorm.Engine, t *testing.T) { - c := new(CustomTableName) - err := engine.DropTables(c) - if err != nil { - t.Error(err) - } - - err = engine.CreateTables(c) - if err != nil { - t.Error(err) - } -} - -func testAll(engine *xorm.Engine, t *testing.T) { - fmt.Println("-------------- directCreateTable --------------") - directCreateTable(engine, t) - fmt.Println("-------------- insert --------------") - insert(engine, t) - fmt.Println("-------------- insertAutoIncr --------------") - insertAutoIncr(engine, t) - fmt.Println("-------------- insertMulti --------------") - insertMulti(engine, t) - fmt.Println("-------------- insertTwoTable --------------") - insertTwoTable(engine, t) - fmt.Println("-------------- testDelete --------------") - testDelete(engine, t) - fmt.Println("-------------- get --------------") - get(engine, t) - fmt.Println("-------------- cascadeGet --------------") - cascadeGet(engine, t) - fmt.Println("-------------- find --------------") - find(engine, t) - fmt.Println("-------------- find2 --------------") - find2(engine, t) - fmt.Println("-------------- findMap --------------") - findMap(engine, t) - fmt.Println("-------------- findMap2 --------------") - findMap2(engine, t) - fmt.Println("-------------- count --------------") - count(engine, t) - fmt.Println("-------------- where --------------") - where(engine, t) - fmt.Println("-------------- in --------------") - in(engine, t) - fmt.Println("-------------- limit --------------") - limit(engine, t) -} - -func testAll2(engine *xorm.Engine, t *testing.T) { - fmt.Println("-------------- table --------------") - table(engine, t) - fmt.Println("-------------- createMultiTables --------------") - createMultiTables(engine, t) - fmt.Println("-------------- tableOp --------------") - tableOp(engine, t) - fmt.Println("-------------- testCharst --------------") - testCharst(engine, t) - fmt.Println("-------------- testStoreEngine --------------") - testStoreEngine(engine, t) - fmt.Println("-------------- testExtends --------------") - testExtends(engine, t) - fmt.Println("-------------- testColTypes --------------") - testColTypes(engine, t) - fmt.Println("-------------- testCustomType --------------") - testCustomType(engine, t) - fmt.Println("-------------- testCreatedAndUpdated --------------") - testCreatedAndUpdated(engine, t) - fmt.Println("-------------- testIndexAndUnique --------------") - testIndexAndUnique(engine, t) - fmt.Println("-------------- testIntId --------------") - testIntId(engine, t) - fmt.Println("-------------- testInt32Id --------------") - testInt32Id(engine, t) - fmt.Println("-------------- testUintId --------------") - testUintId(engine, t) - fmt.Println("-------------- testUint32Id --------------") - testUint32Id(engine, t) - fmt.Println("-------------- testUint64Id --------------") - testUint64Id(engine, t) - fmt.Println("-------------- testMetaInfo --------------") - testMetaInfo(engine, t) - fmt.Println("-------------- testIterate --------------") - testIterate(engine, t) - fmt.Println("-------------- testRows --------------") - testRows(engine, t) - fmt.Println("-------------- testStrangeName --------------") - testStrangeName(engine, t) - fmt.Println("-------------- testVersion --------------") - testVersion(engine, t) - fmt.Println("-------------- testDistinct --------------") - testDistinct(engine, t) - fmt.Println("-------------- testUseBool --------------") - testUseBool(engine, t) - fmt.Println("-------------- testBool --------------") - testBool(engine, t) - fmt.Println("-------------- testTime --------------") - testTime(engine, t) - fmt.Println("-------------- testPrefixTableName --------------") - testPrefixTableName(engine, t) - fmt.Println("-------------- testCreatedUpdated --------------") - testCreatedUpdated(engine, t) - fmt.Println("-------------- testLowercase ---------------") - testLowerCase(engine, t) - fmt.Println("-------------- processors --------------") - testProcessors(engine, t) - fmt.Println("-------------- transaction --------------") - transaction(engine, t) - fmt.Println("-------------- testCustomTableName --------------") - testCustomTableName(engine, t) -} - -// !nash! the 3rd set of the test is intended for non-cache enabled engine -func testAll3(engine *xorm.Engine, t *testing.T) { - fmt.Println("-------------- processors TX --------------") - testProcessorsTx(engine, t) - fmt.Println("-------------- insert pointer data --------------") - testPointerData(engine, t) - fmt.Println("-------------- insert null data --------------") - testNullValue(engine, t) - fmt.Println("-------------- testCompositeKey --------------") - testCompositeKey(engine, t) - fmt.Println("-------------- testCompositeKey2 --------------") - testCompositeKey2(engine, t) - fmt.Println("-------------- testStringPK --------------") - testStringPK(engine, t) -} - -func testAllSnakeMapper(engine *xorm.Engine, t *testing.T) { - fmt.Println("-------------- query --------------") - testQuery(engine, t) - fmt.Println("-------------- exec --------------") - exec(engine, t) - fmt.Println("-------------- update --------------") - update(engine, t) - fmt.Println("-------------- order --------------") - order(engine, t) - fmt.Println("-------------- join --------------") - join(engine, t) - fmt.Println("-------------- having --------------") - having(engine, t) - fmt.Println("-------------- combineTransaction --------------") - combineTransaction(engine, t) - fmt.Println("-------------- testCols --------------") - testCols(engine, t) -} - -func testAllSameMapper(engine *xorm.Engine, t *testing.T) { - fmt.Println("-------------- query --------------") - testQuerySameMapper(engine, t) - fmt.Println("-------------- exec --------------") - execSameMapper(engine, t) - fmt.Println("-------------- update --------------") - updateSameMapper(engine, t) - fmt.Println("-------------- order --------------") - orderSameMapper(engine, t) - fmt.Println("-------------- join --------------") - joinSameMapper(engine, t) - fmt.Println("-------------- having --------------") - havingSameMapper(engine, t) - fmt.Println("-------------- combineTransaction --------------") - combineTransactionSameMapper(engine, t) - fmt.Println("-------------- testCols --------------") - testColsSameMapper(engine, t) -} diff --git a/tests/benchmark.bat b/tests/benchmark.bat deleted file mode 100644 index d35fe044..00000000 --- a/tests/benchmark.bat +++ /dev/null @@ -1 +0,0 @@ -go test -v -bench=. -run=XXX \ No newline at end of file diff --git a/tests/benchmark.sh b/tests/benchmark.sh deleted file mode 100755 index d35fe044..00000000 --- a/tests/benchmark.sh +++ /dev/null @@ -1 +0,0 @@ -go test -v -bench=. -run=XXX \ No newline at end of file diff --git a/tests/benchmark_base_test.go b/tests/benchmark_base_test.go deleted file mode 100644 index d970bd13..00000000 --- a/tests/benchmark_base_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package tests - -import ( - "database/sql" - "testing" - - "github.com/go-xorm/xorm" -) - -type BigStruct struct { - Id int64 - Name string - Title string - Age string - Alias string - NickName string -} - -func doBenchDriverInsert(db *sql.DB, b *testing.B) { - b.StartTimer() - for i := 0; i < b.N; i++ { - _, err := db.Exec(`insert into big_struct (name, title, age, alias, nick_name) - values ('fafdasf', 'fadfa', 'afadfsaf', 'fadfafdsafd', 'fadfafdsaf')`) - if err != nil { - b.Error(err) - return - } - } - b.StopTimer() -} - -func doBenchDriverFind(db *sql.DB, b *testing.B) { - b.StopTimer() - for i := 0; i < 50; i++ { - _, err := db.Exec(`insert into big_struct (name, title, age, alias, nick_name) - values ('fafdasf', 'fadfa', 'afadfsaf', 'fadfafdsafd', 'fadfafdsaf')`) - if err != nil { - b.Error(err) - return - } - } - - b.StartTimer() - for i := 0; i < b.N/50; i++ { - rows, err := db.Query("select * from big_struct limit 50") - if err != nil { - b.Error(err) - return - } - for rows.Next() { - s := &BigStruct{} - rows.Scan(&s.Id, &s.Name, &s.Title, &s.Age, &s.Alias, &s.NickName) - } - } - b.StopTimer() -} - -func doBenchDriver(newdriver func() (*sql.DB, error), createTableSql, - dropTableSql string, opFunc func(*sql.DB, *testing.B), t *testing.B) { - db, err := newdriver() - if err != nil { - t.Error(err) - return - } - defer db.Close() - - _, err = db.Exec(createTableSql) - if err != nil { - t.Error(err) - return - } - - opFunc(db, t) - - _, err = db.Exec(dropTableSql) - if err != nil { - t.Error(err) - return - } -} - -func doBenchInsert(engine *xorm.Engine, b *testing.B) { - b.StopTimer() - bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"} - err := engine.CreateTables(bs) - if err != nil { - b.Error(err) - return - } - - b.StartTimer() - for i := 0; i < b.N; i++ { - bs.Id = 0 - _, err = engine.Insert(bs) - if err != nil { - b.Error(err) - return - } - } - b.StopTimer() - err = engine.DropTables(bs) - if err != nil { - b.Error(err) - return - } -} - -func doBenchFind(engine *xorm.Engine, b *testing.B) { - b.StopTimer() - bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"} - err := engine.CreateTables(bs) - if err != nil { - b.Error(err) - return - } - - for i := 0; i < 100; i++ { - bs.Id = 0 - _, err = engine.Insert(bs) - if err != nil { - b.Error(err) - return - } - } - - b.StartTimer() - for i := 0; i < b.N/50; i++ { - bss := new([]BigStruct) - err = engine.Limit(50).Find(bss) - if err != nil { - b.Error(err) - return - } - } - b.StopTimer() - err = engine.DropTables(bs) - if err != nil { - b.Error(err) - return - } -} - -func doBenchFindPtr(engine *xorm.Engine, b *testing.B) { - b.StopTimer() - bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"} - err := engine.CreateTables(bs) - if err != nil { - b.Error(err) - return - } - - for i := 0; i < 100; i++ { - bs.Id = 0 - _, err = engine.Insert(bs) - if err != nil { - b.Error(err) - return - } - } - - b.StartTimer() - for i := 0; i < b.N/50; i++ { - bss := new([]*BigStruct) - err = engine.Limit(50).Find(bss) - if err != nil { - b.Error(err) - return - } - } - b.StopTimer() - err = engine.DropTables(bs) - if err != nil { - b.Error(err) - return - } -} diff --git a/tests/mssql_test.go b/tests/mssql_test.go deleted file mode 100644 index fac774e1..00000000 --- a/tests/mssql_test.go +++ /dev/null @@ -1,144 +0,0 @@ -package tests - -// -// +build windows - -import ( - "database/sql" - "testing" - - "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" - _ "github.com/lunny/godbc" -) - -const mssqlConnStr = "driver={SQL Server};Server=192.168.20.135;Database=xorm_test; uid=sa; pwd=1234;" - -func newMssqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("odbc", mssqlConnStr) -} - -func TestMssql(t *testing.T) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) -} - -func TestMssqlWithCache(t *testing.T) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) -} - -func newMssqlDriverDB() (*sql.DB, error) { - return sql.Open("odbc", mssqlConnStr) -} - -const ( - createTableMssql = `IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = 'big_struct' ) CREATE TABLE - "big_struct" ("id" BIGINT PRIMARY KEY IDENTITY NOT NULL, "name" VARCHAR(255) NULL, "title" VARCHAR(255) NULL, - "age" VARCHAR(255) NULL, "alias" VARCHAR(255) NULL, "nick_name" VARCHAR(255) NULL); - ` - - dropTableMssql = "IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'big_struct') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE IF EXISTS `big_struct`;" -) - -func BenchmarkMssqlDriverInsert(t *testing.B) { - doBenchDriver(newMssqlDriverDB, createTableMssql, dropTableMssql, - doBenchDriverInsert, t) -} - -func BenchmarkMssqlDriverFind(t *testing.B) { - doBenchDriver(newMssqlDriverDB, createTableMssql, dropTableMssql, - doBenchDriverFind, t) -} - -func BenchmarkMssqlNoCacheInsert(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchInsert(engine, t) -} - -func BenchmarkMssqlNoCacheFind(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkMssqlNoCacheFindPtr(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkMssqlCacheInsert(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchInsert(engine, t) -} - -func BenchmarkMssqlCacheFind(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFind(engine, t) -} - -func BenchmarkMssqlCacheFindPtr(t *testing.B) { - engine, err := newMssqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFindPtr(engine, t) -} diff --git a/tests/mymysql_test.go b/tests/mymysql_test.go deleted file mode 100644 index ef212a2c..00000000 --- a/tests/mymysql_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package tests - -import ( - "database/sql" - "testing" - - "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" - _ "github.com/ziutek/mymysql/godrv" -) - -/* -CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET -utf8 COLLATE utf8_general_ci; -*/ - -var showTestSql bool = true - -func TestMyMysql(t *testing.T) { - err := mymysqlDdlImport() - if err != nil { - t.Error(err) - return - } - engine, err := xorm.NewEngine("mymysql", "xorm_test/root/") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestMyMysqlWithCache(t *testing.T) { - err := mymysqlDdlImport() - if err != nil { - t.Error(err) - return - } - engine, err := xorm.NewEngine("mymysql", "xorm_test2/root/") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAll2(engine, t) -} - -func newMyMysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mymysql", "xorm_test2/root/") -} - -func newMyMysqlDriverDB() (*sql.DB, error) { - return sql.Open("mymysql", "xorm_test2/root/") -} - -func BenchmarkMyMysqlDriverInsert(t *testing.B) { - doBenchDriver(newMyMysqlDriverDB, createTableMySql, dropTableMySql, - doBenchDriverInsert, t) -} - -func BenchmarkMyMysqlDriverFind(t *testing.B) { - doBenchDriver(newMyMysqlDriverDB, createTableMySql, dropTableMySql, - doBenchDriverFind, t) -} - -func mymysqlDdlImport() error { - engine, err := xorm.NewEngine("mymysql", "/root/") - if err != nil { - return err - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - sqlResults, _ := engine.Import("testdata/mysql_ddl.sql") - engine.LogDebug("sql results: %v", sqlResults) - engine.Close() - return nil -} - -func BenchmarkMyMysqlNoCacheInsert(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - defer engine.Close() - - doBenchInsert(engine, t) -} - -func BenchmarkMyMysqlNoCacheFind(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - defer engine.Close() - - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkMyMysqlNoCacheFindPtr(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - defer engine.Close() - - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkMyMysqlCacheInsert(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - - defer engine.Close() - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchInsert(engine, t) -} - -func BenchmarkMyMysqlCacheFind(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - - defer engine.Close() - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFind(engine, t) -} - -func BenchmarkMyMysqlCacheFindPtr(t *testing.B) { - engine, err := newMyMysqlEngine() - if err != nil { - t.Error(err) - return - } - - defer engine.Close() - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFindPtr(engine, t) -} diff --git a/tests/mysql_test.go b/tests/mysql_test.go deleted file mode 100644 index 02a70b39..00000000 --- a/tests/mysql_test.go +++ /dev/null @@ -1,222 +0,0 @@ -package tests - -import ( - "database/sql" - "testing" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" -) - -/* -CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET -utf8 COLLATE utf8_general_ci; -*/ - -func TestMysql(t *testing.T) { - err := mysqlDdlImport() - if err != nil { - t.Error(err) - return - } - - engine, err := xorm.NewEngine("mysql", "root:@/xorm_test?charset=utf8") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestMysqlSameMapper(t *testing.T) { - err := mysqlDdlImport() - if err != nil { - t.Error(err) - return - } - - engine, err := xorm.NewEngine("mysql", "root:@/xorm_test1?charset=utf8") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - engine.SetMapper(core.SameMapper{}) - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestMysqlWithCache(t *testing.T) { - err := mysqlDdlImport() - if err != nil { - t.Error(err) - return - } - - engine, err := xorm.NewEngine("mysql", "root:@/xorm_test2?charset=utf8") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) -} - -func TestMysqlWithCacheSameMapper(t *testing.T) { - err := mysqlDdlImport() - if err != nil { - t.Error(err) - return - } - - engine, err := xorm.NewEngine("mysql", "root:@/xorm_test3?charset=utf8") - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetMapper(core.SameMapper{}) - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) -} - -func newMysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/xorm_test?charset=utf8") -} - -func mysqlDdlImport() error { - engine, err := xorm.NewEngine("mysql", "root:@/?charset=utf8") - if err != nil { - return err - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - sqlResults, _ := engine.Import("testdata/mysql_ddl.sql") - engine.LogDebug("sql results: %v", sqlResults) - engine.Close() - return nil -} - -func newMysqlDriverDB() (*sql.DB, error) { - return sql.Open("mysql", "root:@/xorm_test?charset=utf8") -} - -const ( - createTableMySql = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR(255) NULL, `title` VARCHAR(255) NULL, `age` VARCHAR(255) NULL, `alias` VARCHAR(255) NULL, `nick_name` VARCHAR(255) NULL);" - dropTableMySql = "DROP TABLE IF EXISTS `big_struct`;" -) - -func BenchmarkMysqlDriverInsert(t *testing.B) { - doBenchDriver(newMysqlDriverDB, createTableMySql, dropTableMySql, - doBenchDriverInsert, t) -} - -func BenchmarkMysqlDriverFind(t *testing.B) { - doBenchDriver(newMysqlDriverDB, createTableMySql, dropTableMySql, - doBenchDriverFind, t) -} - -func BenchmarkMysqlNoCacheInsert(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchInsert(engine, t) -} - -func BenchmarkMysqlNoCacheFind(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkMysqlNoCacheFindPtr(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkMysqlCacheInsert(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchInsert(engine, t) -} - -func BenchmarkMysqlCacheFind(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFind(engine, t) -} - -func BenchmarkMysqlCacheFindPtr(t *testing.B) { - engine, err := newMysqlEngine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFindPtr(engine, t) -} diff --git a/tests/postgres_test.go b/tests/postgres_test.go deleted file mode 100644 index 8abee32f..00000000 --- a/tests/postgres_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package tests - -import ( - "database/sql" - "testing" - - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" - _ "github.com/lib/pq" -) - -//var connStr string = "dbname=xorm_test user=lunny password=1234 sslmode=disable" - -var connStr string = "dbname=xorm_test sslmode=disable" - -func newPostgresEngine() (*xorm.Engine, error) { - orm, err := xorm.NewEngine("postgres", connStr) - if err != nil { - return nil, err - } - tables, err := orm.DBMetas() - if err != nil { - return nil, err - } - for _, table := range tables { - _, err = orm.Exec("drop table \"" + table.Name + "\"") - if err != nil { - return nil, err - } - } - - return orm, err -} - -func newPostgresDriverDB() (*sql.DB, error) { - return sql.Open("postgres", connStr) -} - -func TestPostgres(t *testing.T) { - engine, err := newPostgresEngine() - if err != nil { - t.Error(err) - return - } - defer engine.Close() - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestPostgresWithCache(t *testing.T) { - engine, err := newPostgresEngine() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - defer engine.Close() - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) -} - -func TestPostgresSameMapper(t *testing.T) { - engine, err := newPostgresEngine() - if err != nil { - t.Error(err) - return - } - defer engine.Close() - engine.SetMapper(core.SameMapper{}) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestPostgresWithCacheSameMapper(t *testing.T) { - engine, err := newPostgresEngine() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - defer engine.Close() - engine.SetMapper(core.SameMapper{}) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) -} - -const ( - createTablePostgres = `CREATE TABLE IF NOT EXISTS "big_struct" ("id" SERIAL PRIMARY KEY NOT NULL, "name" VARCHAR(255) NULL, "title" VARCHAR(255) NULL, "age" VARCHAR(255) NULL, "alias" VARCHAR(255) NULL, "nick_name" VARCHAR(255) NULL);` - dropTablePostgres = `DROP TABLE IF EXISTS "big_struct";` -) - -func BenchmarkPostgresDriverInsert(t *testing.B) { - doBenchDriver(newPostgresDriverDB, createTablePostgres, dropTablePostgres, - doBenchDriverInsert, t) -} - -func BenchmarkPostgresDriverFind(t *testing.B) { - doBenchDriver(newPostgresDriverDB, createTablePostgres, dropTablePostgres, - doBenchDriverFind, t) -} - -func BenchmarkPostgresNoCacheInsert(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchInsert(engine, t) -} - -func BenchmarkPostgresNoCacheFind(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkPostgresNoCacheFindPtr(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkPostgresCacheInsert(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchInsert(engine, t) -} - -func BenchmarkPostgresCacheFind(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFind(engine, t) -} - -func BenchmarkPostgresCacheFindPtr(t *testing.B) { - engine, err := newPostgresEngine() - - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - - doBenchFindPtr(engine, t) -} diff --git a/tests/sqlite3_test.go b/tests/sqlite3_test.go deleted file mode 100644 index 18cc84a3..00000000 --- a/tests/sqlite3_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package tests - -import ( - "database/sql" - "os" - "testing" - - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" - _ "github.com/mattn/go-sqlite3" -) - -func newSqlite3Engine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./test.db") -} - -func newSqlite3DriverDB() (*sql.DB, error) { - os.Remove("./test.db") - return sql.Open("sqlite3", "./test.db") -} - -func TestSqlite3(t *testing.T) { - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestSqlite3WithCache(t *testing.T) { - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSnakeMapper(engine, t) - testAll2(engine, t) -} - -func TestSqlite3SameMapper(t *testing.T) { - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetMapper(core.SameMapper{}) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) - testAll3(engine, t) -} - -func TestSqlite3WithCacheSameMapper(t *testing.T) { - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetMapper(core.SameMapper{}) - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - engine.ShowSQL = showTestSql - engine.ShowErr = showTestSql - engine.ShowWarn = showTestSql - engine.ShowDebug = showTestSql - - testAll(engine, t) - testAllSameMapper(engine, t) - testAll2(engine, t) -} - -const ( - createTableSqlite3 = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, `title` TEXT NULL, `age` TEXT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL);" - dropTableSqlite3 = "DROP TABLE IF EXISTS `big_struct`;" -) - -func BenchmarkSqlite3DriverInsert(t *testing.B) { - doBenchDriver(newSqlite3DriverDB, createTableSqlite3, dropTableSqlite3, - doBenchDriverInsert, t) -} - -func BenchmarkSqlite3DriverFind(t *testing.B) { - doBenchDriver(newSqlite3DriverDB, createTableSqlite3, dropTableSqlite3, - doBenchDriverFind, t) -} - -func BenchmarkSqlite3NoCacheInsert(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchInsert(engine, t) -} - -func BenchmarkSqlite3NoCacheFind(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFind(engine, t) -} - -func BenchmarkSqlite3NoCacheFindPtr(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - //engine.ShowSQL = true - doBenchFindPtr(engine, t) -} - -func BenchmarkSqlite3CacheInsert(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - doBenchInsert(engine, t) -} - -func BenchmarkSqlite3CacheFind(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - doBenchFind(engine, t) -} - -func BenchmarkSqlite3CacheFindPtr(t *testing.B) { - t.StopTimer() - engine, err := newSqlite3Engine() - defer engine.Close() - if err != nil { - t.Error(err) - return - } - engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000)) - doBenchFindPtr(engine, t) -} diff --git a/tests/testdata/mysql_ddl.sql b/tests/testdata/mysql_ddl.sql deleted file mode 100644 index b1fcca5b..00000000 --- a/tests/testdata/mysql_ddl.sql +++ /dev/null @@ -1,8 +0,0 @@ -DROP DATABASE xorm_test; -DROP DATABASE xorm_test1; -DROP DATABASE xorm_test2; -DROP DATABASE xorm_test3; -CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET utf8 COLLATE utf8_general_ci; -CREATE DATABASE IF NOT EXISTS xorm_test1 CHARACTER SET utf8 COLLATE utf8_general_ci; -CREATE DATABASE IF NOT EXISTS xorm_test2 CHARACTER SET utf8 COLLATE utf8_general_ci; -CREATE DATABASE IF NOT EXISTS xorm_test3 CHARACTER SET utf8 COLLATE utf8_general_ci; From a0919b5371bb2199d7ed07effef829c8c730e87b Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Fri, 11 Apr 2014 17:29:00 +0800 Subject: [PATCH 38/41] remove xorm dir as it's relocated to github.com/go-xorm/cmd --- xorm/.gopmfile | 2 - xorm/README.md | 62 ------ xorm/c++.go | 66 ------- xorm/cmd.go | 78 -------- xorm/go.go | 261 ------------------------- xorm/lang.go | 51 ----- xorm/reverse.go | 288 ---------------------------- xorm/shell.go | 147 -------------- xorm/templates/c++/class.h.tpl | 21 -- xorm/templates/c++/config | 1 - xorm/templates/go/config | 1 - xorm/templates/go/struct.go.tpl | 14 -- xorm/templates/goxorm/config | 3 - xorm/templates/goxorm/struct.go.tpl | 18 -- xorm/xorm.go | 162 ---------------- 15 files changed, 1175 deletions(-) delete mode 100644 xorm/.gopmfile delete mode 100644 xorm/README.md delete mode 100644 xorm/c++.go delete mode 100644 xorm/cmd.go delete mode 100644 xorm/go.go delete mode 100644 xorm/lang.go delete mode 100644 xorm/reverse.go delete mode 100644 xorm/shell.go delete mode 100644 xorm/templates/c++/class.h.tpl delete mode 100644 xorm/templates/c++/config delete mode 100644 xorm/templates/go/config delete mode 100644 xorm/templates/go/struct.go.tpl delete mode 100644 xorm/templates/goxorm/config delete mode 100644 xorm/templates/goxorm/struct.go.tpl delete mode 100644 xorm/xorm.go diff --git a/xorm/.gopmfile b/xorm/.gopmfile deleted file mode 100644 index 6fcf08b9..00000000 --- a/xorm/.gopmfile +++ /dev/null @@ -1,2 +0,0 @@ -[deps] -github.com/go-xorm/xorm=../ \ No newline at end of file diff --git a/xorm/README.md b/xorm/README.md deleted file mode 100644 index f4dbc9e6..00000000 --- a/xorm/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# xorm tools - - -xorm tools is a set of tools for database operation. - -## Install - -`go get github.com/go-xorm/xorm/xorm` - -and you should install the depends below: - -* github.com/go-xorm/xorm - -* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - -* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) - -* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - -* Postgres: [github.com/bylevel/pq](https://github.com/bylevel/pq) - - -## Reverse - -After you installed the tool, you can type - -`xorm help reverse` - -to get help - -example: - -sqlite: -`xorm reverse sqite3 test.db templates/goxorm` - -mysql: -`xorm reverse mysql root:@/xorm_test?charset=utf8 templates/goxorm` - -mymysql: -`xorm reverse mymysql xorm_test2/root/ templates/goxorm` - -postgres: -`xorm reverse postgres "dbname=xorm_test sslmode=disable" templates/goxorm` - -will generated go files in `./model` directory - -## Template and Config - -Now, xorm tool supports go and c++ two languages and have go, goxorm, c++ three of default templates. In template directory, we can put a config file to control how to generating. - -```` -lang=go -genJson=1 -``` - -lang must be go or c++ now. -genJson can be 1 or 0, if 1 then the struct will have json tag. - -## LICENSE - - BSD License - [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/xorm/c++.go b/xorm/c++.go deleted file mode 100644 index f5a0907a..00000000 --- a/xorm/c++.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - //"fmt" - "strings" - "text/template" - - "github.com/go-xorm/core" -) - -var ( - CPlusTmpl LangTmpl = LangTmpl{ - template.FuncMap{"Mapper": mapper.Table2Obj, - "Type": cPlusTypeStr, - "UnTitle": unTitle, - }, - nil, - genCPlusImports, - } -) - -func cPlusTypeStr(col *core.Column) string { - tp := col.SQLType - name := strings.ToUpper(tp.Name) - switch name { - case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.Serial: - return "int" - case core.BigInt, core.BigSerial: - return "__int64" - case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText: - return "tstring" - case core.Date, core.DateTime, core.Time, core.TimeStamp: - return "time_t" - case core.Decimal, core.Numeric: - return "tstring" - case core.Real, core.Float: - return "float" - case core.Double: - return "double" - case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea: - return "tstring" - case core.Bool: - return "bool" - default: - return "tstring" - } - return "" -} - -func genCPlusImports(tables []*core.Table) map[string]string { - imports := make(map[string]string) - - for _, table := range tables { - for _, col := range table.Columns() { - switch cPlusTypeStr(col) { - case "time_t": - imports[``] = `` - case "tstring": - imports[""] = "" - //case "__int64": - // imports[""] = "" - } - } - } - return imports -} diff --git a/xorm/cmd.go b/xorm/cmd.go deleted file mode 100644 index cb326f15..00000000 --- a/xorm/cmd.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" -) - -// A Command is an implementation of a go command -// like go build or go fix. -type Command struct { - // Run runs the command. - // The args are the arguments after the command name. - Run func(cmd *Command, args []string) - - // UsageLine is the one-line usage message. - // The first word in the line is taken to be the command name. - UsageLine string - - // Short is the short description shown in the 'go help' output. - Short string - - // Long is the long message shown in the 'go help ' output. - Long string - - // Flag is a set of flags specific to this command. - Flags map[string]bool -} - -// Name returns the command's name: the first word in the usage line. -func (c *Command) Name() string { - name := c.UsageLine - i := strings.Index(name, " ") - if i >= 0 { - name = name[:i] - } - return name -} - -func (c *Command) Usage() { - fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine) - fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long)) - os.Exit(2) -} - -// Runnable reports whether the command can be run; otherwise -// it is a documentation pseudo-command such as importpath. -func (c *Command) Runnable() bool { - return c.Run != nil -} - -// checkFlags checks if the flag exists with correct format. -func checkFlags(flags map[string]bool, args []string, print func(string)) int { - num := 0 // Number of valid flags, use to cut out. - for i, f := range args { - // Check flag prefix '-'. - if !strings.HasPrefix(f, "-") { - // Not a flag, finish check process. - break - } - - // Check if it a valid flag. - if v, ok := flags[f]; ok { - flags[f] = !v - if !v { - print(f) - } else { - fmt.Println("DISABLE: " + f) - } - } else { - fmt.Printf("[ERRO] Unknown flag: %s.\n", f) - return -1 - } - num = i + 1 - } - - return num -} diff --git a/xorm/go.go b/xorm/go.go deleted file mode 100644 index 382b5b18..00000000 --- a/xorm/go.go +++ /dev/null @@ -1,261 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "go/format" - "reflect" - "strings" - "text/template" - - "github.com/go-xorm/core" -) - -var ( - GoLangTmpl LangTmpl = LangTmpl{ - template.FuncMap{"Mapper": mapper.Table2Obj, - "Type": typestring, - "Tag": tag, - "UnTitle": unTitle, - "gt": gt, - "getCol": getCol, - }, - formatGo, - genGoImports, - } -) - -var ( - errBadComparisonType = errors.New("invalid type for comparison") - errBadComparison = errors.New("incompatible types for comparison") - errNoComparison = errors.New("missing argument for comparison") -) - -type kind int - -const ( - invalidKind kind = iota - boolKind - complexKind - intKind - floatKind - integerKind - stringKind - uintKind -) - -func basicKind(v reflect.Value) (kind, error) { - switch v.Kind() { - case reflect.Bool: - return boolKind, nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return intKind, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return uintKind, nil - case reflect.Float32, reflect.Float64: - return floatKind, nil - case reflect.Complex64, reflect.Complex128: - return complexKind, nil - case reflect.String: - return stringKind, nil - } - return invalidKind, errBadComparisonType -} - -// eq evaluates the comparison a == b || a == c || ... -func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { - v1 := reflect.ValueOf(arg1) - k1, err := basicKind(v1) - if err != nil { - return false, err - } - if len(arg2) == 0 { - return false, errNoComparison - } - for _, arg := range arg2 { - v2 := reflect.ValueOf(arg) - k2, err := basicKind(v2) - if err != nil { - return false, err - } - if k1 != k2 { - return false, errBadComparison - } - truth := false - switch k1 { - case boolKind: - truth = v1.Bool() == v2.Bool() - case complexKind: - truth = v1.Complex() == v2.Complex() - case floatKind: - truth = v1.Float() == v2.Float() - case intKind: - truth = v1.Int() == v2.Int() - case stringKind: - truth = v1.String() == v2.String() - case uintKind: - truth = v1.Uint() == v2.Uint() - default: - panic("invalid kind") - } - if truth { - return true, nil - } - } - return false, nil -} - -// lt evaluates the comparison a < b. -func lt(arg1, arg2 interface{}) (bool, error) { - v1 := reflect.ValueOf(arg1) - k1, err := basicKind(v1) - if err != nil { - return false, err - } - v2 := reflect.ValueOf(arg2) - k2, err := basicKind(v2) - if err != nil { - return false, err - } - if k1 != k2 { - return false, errBadComparison - } - truth := false - switch k1 { - case boolKind, complexKind: - return false, errBadComparisonType - case floatKind: - truth = v1.Float() < v2.Float() - case intKind: - truth = v1.Int() < v2.Int() - case stringKind: - truth = v1.String() < v2.String() - case uintKind: - truth = v1.Uint() < v2.Uint() - default: - panic("invalid kind") - } - return truth, nil -} - -// le evaluates the comparison <= b. -func le(arg1, arg2 interface{}) (bool, error) { - // <= is < or ==. - lessThan, err := lt(arg1, arg2) - if lessThan || err != nil { - return lessThan, err - } - return eq(arg1, arg2) -} - -// gt evaluates the comparison a > b. -func gt(arg1, arg2 interface{}) (bool, error) { - // > is the inverse of <=. - lessOrEqual, err := le(arg1, arg2) - if err != nil { - return false, err - } - return !lessOrEqual, nil -} - -func getCol(cols map[string]*core.Column, name string) *core.Column { - return cols[name] -} - -func formatGo(src string) (string, error) { - source, err := format.Source([]byte(src)) - if err != nil { - return "", err - } - return string(source), nil -} - -func genGoImports(tables []*core.Table) map[string]string { - imports := make(map[string]string) - - for _, table := range tables { - for _, col := range table.Columns() { - if typestring(col) == "time.Time" { - imports["time"] = "time" - } - } - } - return imports -} - -func typestring(col *core.Column) string { - st := col.SQLType - t := core.SQLType2Type(st) - s := t.String() - if s == "[]uint8" { - return "[]byte" - } - return s -} - -func tag(table *core.Table, col *core.Column) string { - isNameId := (mapper.Table2Obj(col.Name) == "Id") - isIdPk := isNameId && typestring(col) == "int64" - - res := make([]string, 0) - if !col.Nullable { - if !isIdPk { - res = append(res, "not null") - } - } - if col.IsPrimaryKey { - if !isIdPk { - res = append(res, "pk") - } - } - if col.Default != "" { - res = append(res, "default "+col.Default) - } - if col.IsAutoIncrement { - if !isIdPk { - res = append(res, "autoincr") - } - } - if col.IsCreated { - res = append(res, "created") - } - if col.IsUpdated { - res = append(res, "updated") - } - for name, _ := range col.Indexes { - index := table.Indexes[name] - var uistr string - if index.Type == core.UniqueType { - uistr = "unique" - } else if index.Type == core.IndexType { - uistr = "index" - } - if len(index.Cols) > 1 { - uistr += "(" + index.Name + ")" - } - res = append(res, uistr) - } - - nstr := col.SQLType.Name - if col.Length != 0 { - if col.Length2 != 0 { - nstr += fmt.Sprintf("(%v,%v)", col.Length, col.Length2) - } else { - nstr += fmt.Sprintf("(%v)", col.Length) - } - } - res = append(res, nstr) - - var tags []string - if genJson { - tags = append(tags, "json:\""+col.Name+"\"") - } - if len(res) > 0 { - tags = append(tags, "xorm:\""+strings.Join(res, " ")+"\"") - } - if len(tags) > 0 { - return "`" + strings.Join(tags, " ") + "`" - } else { - return "" - } -} diff --git a/xorm/lang.go b/xorm/lang.go deleted file mode 100644 index 3af43feb..00000000 --- a/xorm/lang.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "github.com/go-xorm/core" - "io/ioutil" - "strings" - "text/template" -) - -type LangTmpl struct { - Funcs template.FuncMap - Formater func(string) (string, error) - GenImports func([]*core.Table) map[string]string -} - -var ( - mapper = &core.SnakeMapper{} - langTmpls = map[string]LangTmpl{ - "go": GoLangTmpl, - "c++": CPlusTmpl, - } -) - -func loadConfig(f string) map[string]string { - bts, err := ioutil.ReadFile(f) - if err != nil { - return nil - } - configs := make(map[string]string) - lines := strings.Split(string(bts), "\n") - for _, line := range lines { - line = strings.TrimRight(line, "\r") - vs := strings.Split(line, "=") - if len(vs) == 2 { - configs[strings.TrimSpace(vs[0])] = strings.TrimSpace(vs[1]) - } - } - return configs -} - -func unTitle(src string) string { - if src == "" { - return "" - } - - if len(src) == 1 { - return strings.ToLower(string(src[0])) - } else { - return strings.ToLower(string(src[0])) + src[1:] - } -} diff --git a/xorm/reverse.go b/xorm/reverse.go deleted file mode 100644 index 1db8f115..00000000 --- a/xorm/reverse.go +++ /dev/null @@ -1,288 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strconv" - "strings" //[SWH|+] - "text/template" - - _ "github.com/bylevel/pq" - "github.com/dvirsky/go-pylog/logging" - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" - - _ "github.com/mattn/go-sqlite3" - _ "github.com/ziutek/mymysql/godrv" -) - -var CmdReverse = &Command{ - UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]", - Short: "reverse a db to codes", - Long: ` -according database's tables and columns to generate codes for Go, C++ and etc. - - -m Generated one go file for every table - driverName Database driver name, now supported four: mysql mymysql sqlite3 postgres - datasourceName Database connection uri, for detail infomation please visit driver's project page - tmplPath Template dir for generated. the default templates dir has provide 1 template - generatedPath This parameter is optional, if blank, the default value is model, then will - generated all codes in model dir -`, -} - -func init() { - CmdReverse.Run = runReverse - CmdReverse.Flags = map[string]bool{ - "-s": false, - "-l": false, - } -} - -var ( - genJson bool = false -) - -func printReversePrompt(flag string) { -} - -type Tmpl struct { - Tables []*core.Table - Imports map[string]string - Model string -} - -func dirExists(dir string) bool { - d, e := os.Stat(dir) - switch { - case e != nil: - return false - case !d.IsDir(): - return false - } - - return true -} - -func runReverse(cmd *Command, args []string) { - num := checkFlags(cmd.Flags, args, printReversePrompt) - if num == -1 { - return - } - args = args[num:] - - if len(args) < 3 { - fmt.Println("params error, please see xorm help reverse") - return - } - - var isMultiFile bool = true - if use, ok := cmd.Flags["-s"]; ok { - isMultiFile = !use - } - - curPath, err := os.Getwd() - if err != nil { - fmt.Println(curPath) - return - } - - var genDir string - var model string - if len(args) == 4 { - genDir, err = filepath.Abs(args[3]) - if err != nil { - fmt.Println(err) - return - } - - //[SWH|+] 经测试,path.Base不能解析windows下的“\”,需要替换为“/” - genDir = strings.Replace(genDir, "\\", "/", -1) - model = path.Base(genDir) - } else { - model = "model" - genDir = path.Join(curPath, model) - } - - dir, err := filepath.Abs(args[2]) - if err != nil { - logging.Error("%v", err) - return - } - - if !dirExists(dir) { - logging.Error("Template %v path is not exist", dir) - return - } - - var langTmpl LangTmpl - var ok bool - var lang string = "go" - var prefix string = "" //[SWH|+] - - cfgPath := path.Join(dir, "config") - info, err := os.Stat(cfgPath) - var configs map[string]string - if err == nil && !info.IsDir() { - configs = loadConfig(cfgPath) - if l, ok := configs["lang"]; ok { - lang = l - } - if j, ok := configs["genJson"]; ok { - genJson, err = strconv.ParseBool(j) - } - - //[SWH|+] - if j, ok := configs["prefix"]; ok { - prefix = j - } - } - - if langTmpl, ok = langTmpls[lang]; !ok { - fmt.Println("Unsupported programing language", lang) - return - } - - os.MkdirAll(genDir, os.ModePerm) - - Orm, err := xorm.NewEngine(args[0], args[1]) - if err != nil { - logging.Error("%v", err) - return - } - - tables, err := Orm.DBMetas() - if err != nil { - logging.Error("%v", err) - return - } - - filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { - if info.IsDir() { - return nil - } - - if info.Name() == "config" { - return nil - } - - bs, err := ioutil.ReadFile(f) - if err != nil { - logging.Error("%v", err) - return err - } - - t := template.New(f) - t.Funcs(langTmpl.Funcs) - - tmpl, err := t.Parse(string(bs)) - if err != nil { - logging.Error("%v", err) - return err - } - - var w *os.File - fileName := info.Name() - newFileName := fileName[:len(fileName)-4] - ext := path.Ext(newFileName) - - if !isMultiFile { - w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } - - imports := langTmpl.GenImports(tables) - - tbls := make([]*core.Table, 0) - for _, table := range tables { - //[SWH|+] - if prefix != "" { - table.Name = strings.TrimPrefix(table.Name, prefix) - } - tbls = append(tbls, table) - } - - newbytes := bytes.NewBufferString("") - - t := &Tmpl{Tables: tbls, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } - - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v", err) - return err - } - } else { - source = string(tplcontent) - } - - w.WriteString(source) - w.Close() - } else { - for _, table := range tables { - //[SWH|+] - if prefix != "" { - table.Name = strings.TrimPrefix(table.Name, prefix) - } - // imports - tbs := []*core.Table{table} - imports := langTmpl.GenImports(tbs) - - w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } - - newbytes := bytes.NewBufferString("") - - t := &Tmpl{Tables: tbs, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } - - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v-%v", err, string(tplcontent)) - return err - } - } else { - source = string(tplcontent) - } - - w.WriteString(source) - w.Close() - } - } - - return nil - }) - -} diff --git a/xorm/shell.go b/xorm/shell.go deleted file mode 100644 index 5258e4c4..00000000 --- a/xorm/shell.go +++ /dev/null @@ -1,147 +0,0 @@ -package main - -import ( - "fmt" - "github.com/go-xorm/xorm" - "strings" -) - -var CmdShell = &Command{ - UsageLine: "shell driverName datasourceName", - Short: "a general shell to operate all kinds of database", - Long: ` -general database's shell for sqlite3, mysql, postgres. - - driverName Database driver name, now supported four: mysql mymysql sqlite3 postgres - datasourceName Database connection uri, for detail infomation please visit driver's project page -`, -} - -func init() { - CmdShell.Run = runShell - CmdShell.Flags = map[string]bool{} -} - -var engine *xorm.Engine - -func shellHelp() { - fmt.Println(` - show tables show all tables - columns show table's column info - indexes show table's index info - exit exit shell - source exec sql file to current database - dump [-nodata] dump structs or records to sql file - help show this document - SQL statement - `) -} - -func runShell(cmd *Command, args []string) { - if len(args) != 2 { - fmt.Println("params error, please see xorm help shell") - return - } - - var err error - engine, err = xorm.NewEngine(args[0], args[1]) - if err != nil { - fmt.Println(err) - return - } - - err = engine.Ping() - if err != nil { - fmt.Println(err) - return - } - - var scmd string - fmt.Print("xorm$ ") - for { - var input string - _, err := fmt.Scan(&input) - if err != nil { - fmt.Println(err) - continue - } - if strings.ToLower(input) == "exit" { - fmt.Println("bye") - return - } - if !strings.HasSuffix(input, ";") { - scmd = scmd + " " + input - continue - } - scmd = scmd + " " + input - lcmd := strings.TrimSpace(strings.ToLower(scmd)) - if strings.HasPrefix(lcmd, "select") { - res, err := engine.Query(scmd + "\n") - if err != nil { - fmt.Println(err) - } else { - if len(res) <= 0 { - fmt.Println("no records") - } else { - columns := make(map[string]int) - for k, _ := range res[0] { - columns[k] = len(k) - } - - for _, m := range res { - for k, s := range m { - l := len(string(s)) - if l > columns[k] { - columns[k] = l - } - } - } - - var maxlen = 0 - for _, l := range columns { - maxlen = maxlen + l + 3 - } - maxlen = maxlen + 1 - - fmt.Println(strings.Repeat("-", maxlen)) - fmt.Print("|") - slice := make([]string, 0) - for k, l := range columns { - fmt.Print(" " + k + " ") - fmt.Print(strings.Repeat(" ", l-len(k))) - fmt.Print("|") - slice = append(slice, k) - } - fmt.Print("\n") - for _, r := range res { - fmt.Print("|") - for _, k := range slice { - fmt.Print(" " + string(r[k]) + " ") - fmt.Print(strings.Repeat(" ", columns[k]-len(string(r[k])))) - fmt.Print("|") - } - fmt.Print("\n") - } - fmt.Println(strings.Repeat("-", maxlen)) - //fmt.Println(res) - } - } - } else if lcmd == "show tables;" { - /*tables, err := engine.DBMetas() - if err != nil { - fmt.Println(err) - } else { - - }*/ - } else { - cnt, err := engine.Exec(scmd) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("%d records changed.\n", cnt) - } - } - scmd = "" - fmt.Print("xorm$ ") - } -} diff --git a/xorm/templates/c++/class.h.tpl b/xorm/templates/c++/class.h.tpl deleted file mode 100644 index 50a32ff8..00000000 --- a/xorm/templates/c++/class.h.tpl +++ /dev/null @@ -1,21 +0,0 @@ -{{ range .Imports}} -#include {{.}} -{{ end }} - -{{range .Tables}}class {{Mapper .Name}} { -{{$table := .}} -public: -{{range .Columns}}{{$name := Mapper .Name}} {{Type .}} Get{{Mapper .Name}}() { - return this->m_{{UnTitle $name}}; - } - - void Set{{$name}}({{Type .}} {{UnTitle $name}}) { - this->m_{{UnTitle $name}} = {{UnTitle $name}}; - } - -{{end}}private: -{{range .Columns}}{{$name := Mapper .Name}} {{Type .}} m_{{UnTitle $name}}; -{{end}} -} - -{{end}} \ No newline at end of file diff --git a/xorm/templates/c++/config b/xorm/templates/c++/config deleted file mode 100644 index 4965bae3..00000000 --- a/xorm/templates/c++/config +++ /dev/null @@ -1 +0,0 @@ -lang=c++ \ No newline at end of file diff --git a/xorm/templates/go/config b/xorm/templates/go/config deleted file mode 100644 index 6fdeea2b..00000000 --- a/xorm/templates/go/config +++ /dev/null @@ -1 +0,0 @@ -lang=go \ No newline at end of file diff --git a/xorm/templates/go/struct.go.tpl b/xorm/templates/go/struct.go.tpl deleted file mode 100644 index 8e59d688..00000000 --- a/xorm/templates/go/struct.go.tpl +++ /dev/null @@ -1,14 +0,0 @@ -package {{.Model}} - -import ( - {{range .Imports}}"{{.}}"{{end}} -) - -{{range .Tables}} -type {{Mapper .Name}} struct { -{{$table := .}} -{{range .Columns}} {{Mapper .Name}} {{Type .}} -{{end}} -} - -{{end}} \ No newline at end of file diff --git a/xorm/templates/goxorm/config b/xorm/templates/goxorm/config deleted file mode 100644 index 5d7bf321..00000000 --- a/xorm/templates/goxorm/config +++ /dev/null @@ -1,3 +0,0 @@ -lang=go -genJson=0 -prefix=cos_ diff --git a/xorm/templates/goxorm/struct.go.tpl b/xorm/templates/goxorm/struct.go.tpl deleted file mode 100644 index 91b00854..00000000 --- a/xorm/templates/goxorm/struct.go.tpl +++ /dev/null @@ -1,18 +0,0 @@ -package {{.Model}} - -{{$ilen := len .Imports}} -{{if gt $ilen 0}} -import ( - {{range .Imports}}"{{.}}"{{end}} -) -{{end}} - -{{range .Tables}} -type {{Mapper .Name}} struct { -{{$table := .}} -{{$columns := .Columns}} -{{range .ColumnsSeq}}{{$col := getCol $columns .}} {{Mapper $col.Name}} {{Type $col}} {{Tag $table $col}} -{{end}} -} - -{{end}} \ No newline at end of file diff --git a/xorm/xorm.go b/xorm/xorm.go deleted file mode 100644 index 11235e88..00000000 --- a/xorm/xorm.go +++ /dev/null @@ -1,162 +0,0 @@ -package main - -import ( - "fmt" - "github.com/dvirsky/go-pylog/logging" - "io" - "os" - "runtime" - "strings" - "sync" - "text/template" - "unicode" - "unicode/utf8" -) - -// +build go1.1 - -// Test that go1.1 tag above is included in builds. main.go refers to this definition. -const go11tag = true - -const version = "0.1" - -// Commands lists the available commands and help topics. -// The order here is the order in which they are printed by 'gopm help'. -var commands = []*Command{ - CmdReverse, - CmdShell, -} - -func init() { - runtime.GOMAXPROCS(runtime.NumCPU()) -} - -func main() { - logging.SetLevel(logging.ALL) - // Check length of arguments. - args := os.Args[1:] - if len(args) < 1 { - usage() - return - } - - // Show help documentation. - if args[0] == "help" { - help(args[1:]) - return - } - - // Check commands and run. - for _, comm := range commands { - if comm.Name() == args[0] && comm.Run != nil { - comm.Run(comm, args[1:]) - exit() - return - } - } - - fmt.Fprintf(os.Stderr, "xorm: unknown subcommand %q\nRun 'xorm help' for usage.\n", args[0]) - setExitStatus(2) - exit() -} - -var exitStatus = 0 -var exitMu sync.Mutex - -func setExitStatus(n int) { - exitMu.Lock() - if exitStatus < n { - exitStatus = n - } - exitMu.Unlock() -} - -var usageTemplate = `xorm is a database tool based xorm package. -Usage: - - xorm command [arguments] - -The commands are: -{{range .}}{{if .Runnable}} - {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} - -Use "xorm help [command]" for more information about a command. - -Additional help topics: -{{range .}}{{if not .Runnable}} - {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} - -Use "xorm help [topic]" for more information about that topic. - -` - -var helpTemplate = `{{if .Runnable}}usage: xorm {{.UsageLine}} - -{{end}}{{.Long | trim}} -` - -// tmpl executes the given template text on data, writing the result to w. -func tmpl(w io.Writer, text string, data interface{}) { - t := template.New("top") - t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) - template.Must(t.Parse(text)) - if err := t.Execute(w, data); err != nil { - panic(err) - } -} - -func capitalize(s string) string { - if s == "" { - return s - } - r, n := utf8.DecodeRuneInString(s) - return string(unicode.ToTitle(r)) + s[n:] -} - -func printUsage(w io.Writer) { - tmpl(w, usageTemplate, commands) -} - -func usage() { - printUsage(os.Stderr) - os.Exit(2) -} - -// help implements the 'help' command. -func help(args []string) { - if len(args) == 0 { - printUsage(os.Stdout) - // not exit 2: succeeded at 'gopm help'. - return - } - if len(args) != 1 { - fmt.Fprintf(os.Stderr, "usage: xorm help command\n\nToo many arguments given.\n") - os.Exit(2) // failed at 'gopm help' - } - - arg := args[0] - - for _, cmd := range commands { - if cmd.Name() == arg { - tmpl(os.Stdout, helpTemplate, cmd) - // not exit 2: succeeded at 'gopm help cmd'. - return - } - } - - fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'xorm help'.\n", arg) - os.Exit(2) // failed at 'gopm help cmd' -} - -var atexitFuncs []func() - -func atexit(f func()) { - atexitFuncs = append(atexitFuncs, f) -} - -func exit() { - for _, f := range atexitFuncs { - f() - } - os.Exit(exitStatus) -} From 81c947b61b7290945679a5a33100297d35aeb514 Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Fri, 11 Apr 2014 21:06:11 +0800 Subject: [PATCH 39/41] flattened dialects dir and register db dialect for assocaited registered driver --- dialects/mssql.go => mssql_dialect.go | 100 +++++++++---------- dialects/mysql.go => mysql_dialect.go | 74 +++++++------- dialects/oracle.go => oracle_dialect.go | 78 +++++++-------- dialects/postgres.go => postgres_dialect.go | 104 ++++++++++---------- dialects/sqlite3.go => sqlite3_dialect.go | 82 +++++++-------- xorm.go | 23 ++++- 6 files changed, 241 insertions(+), 220 deletions(-) rename dialects/mssql.go => mssql_dialect.go (76%) rename dialects/mysql.go => mysql_dialect.go (81%) rename dialects/oracle.go => oracle_dialect.go (71%) rename dialects/postgres.go => postgres_dialect.go (71%) rename dialects/sqlite3.go => sqlite3_dialect.go (71%) diff --git a/dialects/mssql.go b/mssql_dialect.go similarity index 76% rename from dialects/mssql.go rename to mssql_dialect.go index 10ec3ad7..0b85f6a9 100644 --- a/dialects/mssql.go +++ b/mssql_dialect.go @@ -1,4 +1,4 @@ -package dialects +package xorm import ( "errors" @@ -6,58 +6,58 @@ import ( "strconv" "strings" - . "github.com/go-xorm/core" + "github.com/go-xorm/core" ) -func init() { - RegisterDialect("mssql", &mssql{}) -} +// func init() { +// RegisterDialect("mssql", &mssql{}) +// } type mssql struct { - Base + core.Base } -func (db *mssql) Init(uri *Uri, drivername, dataSourceName string) error { +func (db *mssql) Init(uri *core.Uri, drivername, dataSourceName string) error { return db.Base.Init(db, uri, drivername, dataSourceName) } -func (db *mssql) SqlType(c *Column) string { +func (db *mssql) SqlType(c *core.Column) string { var res string switch t := c.SQLType.Name; t { - case Bool: - res = TinyInt - case Serial: + case core.Bool: + res = core.TinyInt + case core.Serial: c.IsAutoIncrement = true c.IsPrimaryKey = true c.Nullable = false - res = Int - case BigSerial: + res = core.Int + case core.BigSerial: c.IsAutoIncrement = true c.IsPrimaryKey = true c.Nullable = false - res = BigInt - case Bytea, Blob, Binary, TinyBlob, MediumBlob, LongBlob: - res = VarBinary + res = core.BigInt + case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob: + res = core.VarBinary if c.Length == 0 { c.Length = 50 } - case TimeStamp: - res = DateTime - case TimeStampz: + case core.TimeStamp: + res = core.DateTime + case core.TimeStampz: res = "DATETIMEOFFSET" c.Length = 7 - case MediumInt: - res = Int - case MediumText, TinyText, LongText: - res = Text - case Double: - res = Real + case core.MediumInt: + res = core.Int + case core.MediumText, core.TinyText, core.LongText: + res = core.Text + case core.Double: + res = core.Real default: res = t } - if res == Int { - return Int + if res == core.Int { + return core.Int } var hasLen1 bool = (c.Length > 0) @@ -118,12 +118,12 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { return sql, args } -func (db *mssql) GetColumns(tableName string) ([]string, map[string]*Column, error) { +func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{} s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id where a.object_id=object_id('` + tableName + `')` - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, nil, err } @@ -133,7 +133,7 @@ where a.object_id=object_id('` + tableName + `')` if err != nil { return nil, nil, err } - cols := make(map[string]*Column) + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for rows.Next() { var name, ctype, precision, scale string @@ -143,7 +143,7 @@ where a.object_id=object_id('` + tableName + `')` return nil, nil, err } - col := new(Column) + col := new(core.Column) col.Indexes = make(map[string]bool) col.Length = maxLen col.Name = strings.Trim(name, "` ") @@ -151,14 +151,14 @@ where a.object_id=object_id('` + tableName + `')` ct := strings.ToUpper(ctype) switch ct { case "DATETIMEOFFSET": - col.SQLType = SQLType{TimeStampz, 0, 0} + col.SQLType = core.SQLType{core.TimeStampz, 0, 0} case "NVARCHAR": - col.SQLType = SQLType{Varchar, 0, 0} + col.SQLType = core.SQLType{core.Varchar, 0, 0} case "IMAGE": - col.SQLType = SQLType{VarBinary, 0, 0} + col.SQLType = core.SQLType{core.VarBinary, 0, 0} default: - if _, ok := SqlTypes[ct]; ok { - col.SQLType = SQLType{ct, 0, 0} + if _, ok := core.SqlTypes[ct]; ok { + col.SQLType = core.SQLType{ct, 0, 0} } else { return nil, nil, errors.New(fmt.Sprintf("unknow colType %v for %v - %v", ct, tableName, col.Name)) @@ -180,10 +180,10 @@ where a.object_id=object_id('` + tableName + `')` return colSeq, cols, nil } -func (db *mssql) GetTables() ([]*Table, error) { +func (db *mssql) GetTables() ([]*core.Table, error) { args := []interface{}{} s := `select name from sysobjects where xtype ='U'` - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -193,9 +193,9 @@ func (db *mssql) GetTables() ([]*Table, error) { return nil, err } - tables := make([]*Table, 0) + tables := make([]*core.Table, 0) for rows.Next() { - table := NewEmptyTable() + table := core.NewEmptyTable() var name string err = rows.Scan(&name) if err != nil { @@ -207,7 +207,7 @@ func (db *mssql) GetTables() ([]*Table, error) { return tables, nil } -func (db *mssql) GetIndexes(tableName string) (map[string]*Index, error) { +func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{tableName} s := `SELECT IXS.NAME AS [INDEX_NAME], @@ -223,7 +223,7 @@ INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID AND IXCS.COLUMN_ID=C.COLUMN_ID WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? ` - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -233,7 +233,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? return nil, err } - indexes := make(map[string]*Index, 0) + indexes := make(map[string]*core.Index, 0) for rows.Next() { var indexType int var indexName, colName, isUnique string @@ -249,9 +249,9 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? } if i { - indexType = UniqueType + indexType = core.UniqueType } else { - indexType = IndexType + indexType = core.IndexType } colName = strings.Trim(colName, "` ") @@ -260,10 +260,10 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? indexName = indexName[5+len(tableName) : len(indexName)] } - var index *Index + var index *core.Index var ok bool if index, ok = indexes[indexName]; !ok { - index = new(Index) + index = new(core.Index) index.Type = indexType index.Name = indexName indexes[indexName] = index @@ -273,7 +273,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? return indexes, nil } -func (db *mssql) CreateTablSql(table *Table, tableName, storeEngine, charset string) string { +func (db *mssql) CreateTablSql(table *core.Table, tableName, storeEngine, charset string) string { var sql string if tableName == "" { tableName = table.Name @@ -307,6 +307,6 @@ func (db *mssql) CreateTablSql(table *Table, tableName, storeEngine, charset str return sql } -func (db *mssql) Filters() []Filter { - return []Filter{&IdFilter{}, &QuoteFilter{}} +func (db *mssql) Filters() []core.Filter { + return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}} } diff --git a/dialects/mysql.go b/mysql_dialect.go similarity index 81% rename from dialects/mysql.go rename to mysql_dialect.go index ffba757c..52a8a15e 100644 --- a/dialects/mysql.go +++ b/mysql_dialect.go @@ -1,4 +1,4 @@ -package dialects +package xorm import ( "crypto/tls" @@ -8,15 +8,15 @@ import ( "strings" "time" - . "github.com/go-xorm/core" + "github.com/go-xorm/core" ) -func init() { - RegisterDialect("mysql", &mysql{}) -} +// func init() { +// RegisterDialect("mysql", &mysql{}) +// } type mysql struct { - Base + core.Base net string addr string params map[string]string @@ -28,30 +28,30 @@ type mysql struct { clientFoundRows bool } -func (db *mysql) Init(uri *Uri, drivername, dataSourceName string) error { +func (db *mysql) Init(uri *core.Uri, drivername, dataSourceName string) error { return db.Base.Init(db, uri, drivername, dataSourceName) } -func (db *mysql) SqlType(c *Column) string { +func (db *mysql) SqlType(c *core.Column) string { var res string switch t := c.SQLType.Name; t { - case Bool: - res = TinyInt + case core.Bool: + res = core.TinyInt c.Length = 1 - case Serial: + case core.Serial: c.IsAutoIncrement = true c.IsPrimaryKey = true c.Nullable = false - res = Int - case BigSerial: + res = core.Int + case core.BigSerial: c.IsAutoIncrement = true c.IsPrimaryKey = true c.Nullable = false - res = BigInt - case Bytea: - res = Blob - case TimeStampz: - res = Char + res = core.BigInt + case core.Bytea: + res = core.Blob + case core.TimeStampz: + res = core.Char c.Length = 64 default: res = t @@ -110,11 +110,11 @@ func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) { return sql, args } -func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, error) { +func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{db.DbName, tableName} s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + " `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, nil, err } @@ -123,10 +123,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err if err != nil { return nil, nil, err } - cols := make(map[string]*Column) + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for rows.Next() { - col := new(Column) + col := new(core.Column) col.Indexes = make(map[string]bool) var columnName, isNullable, colType, colKey, extra string @@ -164,8 +164,8 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err colType = strings.ToUpper(colName) col.Length = len1 col.Length2 = len2 - if _, ok := SqlTypes[colType]; ok { - col.SQLType = SQLType{colType, len1, len2} + if _, ok := core.SqlTypes[colType]; ok { + col.SQLType = core.SQLType{colType, len1, len2} } else { return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType)) } @@ -192,10 +192,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err return colSeq, cols, nil } -func (db *mysql) GetTables() ([]*Table, error) { +func (db *mysql) GetTables() ([]*core.Table, error) { args := []interface{}{db.DbName} s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=?" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -205,9 +205,9 @@ func (db *mysql) GetTables() ([]*Table, error) { return nil, err } - tables := make([]*Table, 0) + tables := make([]*core.Table, 0) for rows.Next() { - table := NewEmptyTable() + table := core.NewEmptyTable() var name, engine, tableRows string var autoIncr *string err = rows.Scan(&name, &engine, &tableRows, &autoIncr) @@ -221,10 +221,10 @@ func (db *mysql) GetTables() ([]*Table, error) { return tables, nil } -func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) { +func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{db.DbName, tableName} s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -234,7 +234,7 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) { return nil, err } - indexes := make(map[string]*Index, 0) + indexes := make(map[string]*core.Index, 0) for rows.Next() { var indexType int var indexName, colName, nonUnique string @@ -248,9 +248,9 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) { } if "YES" == nonUnique || nonUnique == "1" { - indexType = IndexType + indexType = core.IndexType } else { - indexType = UniqueType + indexType = core.UniqueType } colName = strings.Trim(colName, "` ") @@ -259,10 +259,10 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) { indexName = indexName[5+len(tableName) : len(indexName)] } - var index *Index + var index *core.Index var ok bool if index, ok = indexes[indexName]; !ok { - index = new(Index) + index = new(core.Index) index.Type = indexType index.Name = indexName indexes[indexName] = index @@ -272,6 +272,6 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) { return indexes, nil } -func (db *mysql) Filters() []Filter { - return []Filter{&IdFilter{}} +func (db *mysql) Filters() []core.Filter { + return []core.Filter{&core.IdFilter{}} } diff --git a/dialects/oracle.go b/oracle_dialect.go similarity index 71% rename from dialects/oracle.go rename to oracle_dialect.go index b86a74fc..febd318e 100644 --- a/dialects/oracle.go +++ b/oracle_dialect.go @@ -1,4 +1,4 @@ -package dialects +package xorm import ( "errors" @@ -6,37 +6,37 @@ import ( "strconv" "strings" - . "github.com/go-xorm/core" + "github.com/go-xorm/core" ) -func init() { - RegisterDialect("oracle", &oracle{}) -} +// func init() { +// RegisterDialect("oracle", &oracle{}) +// } type oracle struct { - Base + core.Base } -func (db *oracle) Init(uri *Uri, drivername, dataSourceName string) error { +func (db *oracle) Init(uri *core.Uri, drivername, dataSourceName string) error { return db.Base.Init(db, uri, drivername, dataSourceName) } -func (db *oracle) SqlType(c *Column) string { +func (db *oracle) SqlType(c *core.Column) string { var res string switch t := c.SQLType.Name; t { - case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool, Serial, BigSerial: + case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial: return "NUMBER" - case Binary, VarBinary, Blob, TinyBlob, MediumBlob, LongBlob, Bytea: - return Blob - case Time, DateTime, TimeStamp: - res = TimeStamp - case TimeStampz: + case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea: + return core.Blob + case core.Time, core.DateTime, core.TimeStamp: + res = core.TimeStamp + case core.TimeStampz: res = "TIMESTAMP WITH TIME ZONE" - case Float, Double, Numeric, Decimal: + case core.Float, core.Double, core.Numeric, core.Decimal: res = "NUMBER" - case Text, MediumText, LongText: + case core.Text, core.MediumText, core.LongText: res = "CLOB" - case Char, Varchar, TinyText: + case core.Char, core.Varchar, core.TinyText: return "VARCHAR2" default: res = t @@ -93,12 +93,12 @@ func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface " AND column_name = ?", args } -func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, error) { +func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{strings.ToUpper(tableName)} s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," + "nullable FROM USER_TAB_COLUMNS WHERE table_name = :1" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, nil, err } @@ -109,10 +109,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er } defer rows.Close() - cols := make(map[string]*Column) + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for rows.Next() { - col := new(Column) + col := new(core.Column) col.Indexes = make(map[string]bool) var colName, colDefault, nullable, dataType, dataPrecision, dataScale string @@ -135,13 +135,13 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er switch dataType { case "VARCHAR2": - col.SQLType = SQLType{Varchar, 0, 0} + col.SQLType = core.SQLType{core.Varchar, 0, 0} case "TIMESTAMP WITH TIME ZONE": - col.SQLType = SQLType{TimeStampz, 0, 0} + col.SQLType = core.SQLType{core.TimeStampz, 0, 0} default: - col.SQLType = SQLType{strings.ToUpper(dataType), 0, 0} + col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0} } - if _, ok := SqlTypes[col.SQLType.Name]; !ok { + if _, ok := core.SqlTypes[col.SQLType.Name]; !ok { return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType)) } @@ -163,10 +163,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er return colSeq, cols, nil } -func (db *oracle) GetTables() ([]*Table, error) { +func (db *oracle) GetTables() ([]*core.Table, error) { args := []interface{}{} s := "SELECT table_name FROM user_tables" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -176,9 +176,9 @@ func (db *oracle) GetTables() ([]*Table, error) { return nil, err } - tables := make([]*Table, 0) + tables := make([]*core.Table, 0) for rows.Next() { - table := NewEmptyTable() + table := core.NewEmptyTable() err = rows.Scan(&table.Name) if err != nil { return nil, err @@ -189,12 +189,12 @@ func (db *oracle) GetTables() ([]*Table, error) { return tables, nil } -func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) { +func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{tableName} s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " + "WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -205,7 +205,7 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) { } defer rows.Close() - indexes := make(map[string]*Index, 0) + indexes := make(map[string]*core.Index, 0) for rows.Next() { var indexType int var indexName, colName, uniqueness string @@ -218,15 +218,15 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) { indexName = strings.Trim(indexName, `" `) if uniqueness == "UNIQUE" { - indexType = UniqueType + indexType = core.UniqueType } else { - indexType = IndexType + indexType = core.IndexType } - var index *Index + var index *core.Index var ok bool if index, ok = indexes[indexName]; !ok { - index = new(Index) + index = new(core.Index) index.Type = indexType index.Name = indexName indexes[indexName] = index @@ -240,7 +240,7 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) { type OracleSeqFilter struct { } -func (s *OracleSeqFilter) Do(sql string, dialect Dialect, table *Table) string { +func (s *OracleSeqFilter) Do(sql string, dialect core.Dialect, table *core.Table) string { counts := strings.Count(sql, "?") for i := 1; i <= counts; i++ { newstr := ":" + fmt.Sprintf("%v", i) @@ -249,6 +249,6 @@ func (s *OracleSeqFilter) Do(sql string, dialect Dialect, table *Table) string { return sql } -func (db *oracle) Filters() []Filter { - return []Filter{&QuoteFilter{}, &OracleSeqFilter{}, &IdFilter{}} +func (db *oracle) Filters() []core.Filter { + return []core.Filter{&core.QuoteFilter{}, &OracleSeqFilter{}, &core.IdFilter{}} } diff --git a/dialects/postgres.go b/postgres_dialect.go similarity index 71% rename from dialects/postgres.go rename to postgres_dialect.go index d365732e..58d39f9d 100644 --- a/dialects/postgres.go +++ b/postgres_dialect.go @@ -1,4 +1,4 @@ -package dialects +package xorm import ( "errors" @@ -6,53 +6,53 @@ import ( "strconv" "strings" - . "github.com/go-xorm/core" + "github.com/go-xorm/core" ) -func init() { - RegisterDialect("postgres", &postgres{}) -} +// func init() { +// RegisterDialect("postgres", &postgres{}) +// } type postgres struct { - Base + core.Base } -func (db *postgres) Init(uri *Uri, drivername, dataSourceName string) error { +func (db *postgres) Init(uri *core.Uri, drivername, dataSourceName string) error { return db.Base.Init(db, uri, drivername, dataSourceName) } -func (db *postgres) SqlType(c *Column) string { +func (db *postgres) SqlType(c *core.Column) string { var res string switch t := c.SQLType.Name; t { - case TinyInt: - res = SmallInt + case core.TinyInt: + res = core.SmallInt return res - case MediumInt, Int, Integer: + case core.MediumInt, core.Int, core.Integer: if c.IsAutoIncrement { - return Serial + return core.Serial } - return Integer - case Serial, BigSerial: + return core.Integer + case core.Serial, core.BigSerial: c.IsAutoIncrement = true c.Nullable = false res = t - case Binary, VarBinary: - return Bytea - case DateTime: - res = TimeStamp - case TimeStampz: + case core.Binary, core.VarBinary: + return core.Bytea + case core.DateTime: + res = core.TimeStamp + case core.TimeStampz: return "timestamp with time zone" - case Float: - res = Real - case TinyText, MediumText, LongText: - res = Text - case Blob, TinyBlob, MediumBlob, LongBlob: - return Bytea - case Double: + case core.Float: + res = core.Real + case core.TinyText, core.MediumText, core.LongText: + res = core.Text + case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob: + return core.Bytea + case core.Double: return "DOUBLE PRECISION" default: if c.IsAutoIncrement { - return Serial + return core.Serial } res = t } @@ -108,11 +108,11 @@ func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interfa " AND column_name = ?", args } -func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, error) { +func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{tableName} s := "SELECT column_name, column_default, is_nullable, data_type, character_maximum_length" + ", numeric_precision, numeric_precision_radix FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, nil, err } @@ -121,11 +121,11 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, if err != nil { return nil, nil, err } - cols := make(map[string]*Column) + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for rows.Next() { - col := new(Column) + col := new(core.Column) col.Indexes = make(map[string]bool) var colName, isNullable, dataType string @@ -161,21 +161,21 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, switch dataType { case "character varying", "character": - col.SQLType = SQLType{Varchar, 0, 0} + col.SQLType = core.SQLType{core.Varchar, 0, 0} case "timestamp without time zone": - col.SQLType = SQLType{DateTime, 0, 0} + col.SQLType = core.SQLType{core.DateTime, 0, 0} case "timestamp with time zone": - col.SQLType = SQLType{TimeStampz, 0, 0} + col.SQLType = core.SQLType{core.TimeStampz, 0, 0} case "double precision": - col.SQLType = SQLType{Double, 0, 0} + col.SQLType = core.SQLType{core.Double, 0, 0} case "boolean": - col.SQLType = SQLType{Bool, 0, 0} + col.SQLType = core.SQLType{core.Bool, 0, 0} case "time without time zone": - col.SQLType = SQLType{Time, 0, 0} + col.SQLType = core.SQLType{core.Time, 0, 0} default: - col.SQLType = SQLType{strings.ToUpper(dataType), 0, 0} + col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0} } - if _, ok := SqlTypes[col.SQLType.Name]; !ok { + if _, ok := core.SqlTypes[col.SQLType.Name]; !ok { return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType)) } @@ -197,10 +197,10 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, return colSeq, cols, nil } -func (db *postgres) GetTables() ([]*Table, error) { +func (db *postgres) GetTables() ([]*core.Table, error) { args := []interface{}{} s := "SELECT tablename FROM pg_tables where schemaname = 'public'" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -210,9 +210,9 @@ func (db *postgres) GetTables() ([]*Table, error) { return nil, err } - tables := make([]*Table, 0) + tables := make([]*core.Table, 0) for rows.Next() { - table := NewEmptyTable() + table := core.NewEmptyTable() var name string err = rows.Scan(&name) if err != nil { @@ -224,11 +224,11 @@ func (db *postgres) GetTables() ([]*Table, error) { return tables, nil } -func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) { +func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{tableName} s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' and tablename = $1" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -238,7 +238,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) { return nil, err } - indexes := make(map[string]*Index, 0) + indexes := make(map[string]*core.Index, 0) for rows.Next() { var indexType int var indexName, indexdef string @@ -250,9 +250,9 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) { indexName = strings.Trim(indexName, `" `) if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") { - indexType = UniqueType + indexType = core.UniqueType } else { - indexType = IndexType + indexType = core.IndexType } cs := strings.Split(indexdef, "(") colNames = strings.Split(cs[1][0:len(cs[1])-1], ",") @@ -267,7 +267,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) { } } - index := &Index{Name: indexName, Type: indexType, Cols: make([]string, 0)} + index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)} for _, colName := range colNames { index.Cols = append(index.Cols, strings.Trim(colName, `" `)) } @@ -280,7 +280,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) { type PgSeqFilter struct { } -func (s *PgSeqFilter) Do(sql string, dialect Dialect, table *Table) string { +func (s *PgSeqFilter) Do(sql string, dialect core.Dialect, table *core.Table) string { segs := strings.Split(sql, "?") size := len(segs) res := "" @@ -293,6 +293,6 @@ func (s *PgSeqFilter) Do(sql string, dialect Dialect, table *Table) string { return res } -func (db *postgres) Filters() []Filter { - return []Filter{&IdFilter{}, &QuoteFilter{}, &PgSeqFilter{}} +func (db *postgres) Filters() []core.Filter { + return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &PgSeqFilter{}} } diff --git a/dialects/sqlite3.go b/sqlite3_dialect.go similarity index 71% rename from dialects/sqlite3.go rename to sqlite3_dialect.go index aa829424..d5be5c72 100644 --- a/dialects/sqlite3.go +++ b/sqlite3_dialect.go @@ -1,44 +1,44 @@ -package dialects +package xorm import ( "strings" - . "github.com/go-xorm/core" + "github.com/go-xorm/core" ) -func init() { - RegisterDialect("sqlite3", &sqlite3{}) -} +// func init() { +// RegisterDialect("sqlite3", &sqlite3{}) +// } type sqlite3 struct { - Base + core.Base } -func (db *sqlite3) Init(uri *Uri, drivername, dataSourceName string) error { +func (db *sqlite3) Init(uri *core.Uri, drivername, dataSourceName string) error { return db.Base.Init(db, uri, drivername, dataSourceName) } -func (db *sqlite3) SqlType(c *Column) string { +func (db *sqlite3) SqlType(c *core.Column) string { switch t := c.SQLType.Name; t { - case Date, DateTime, TimeStamp, Time: - return Numeric - case TimeStampz: - return Text - case Char, Varchar, TinyText, Text, MediumText, LongText: - return Text - case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool: - return Integer - case Float, Double, Real: - return Real - case Decimal, Numeric: - return Numeric - case TinyBlob, Blob, MediumBlob, LongBlob, Bytea, Binary, VarBinary: - return Blob - case Serial, BigSerial: + case core.Date, core.DateTime, core.TimeStamp, core.Time: + return core.Numeric + case core.TimeStampz: + return core.Text + case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText: + return core.Text + case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool: + return core.Integer + case core.Float, core.Double, core.Real: + return core.Real + case core.Decimal, core.Numeric: + return core.Numeric + case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary: + return core.Blob + case core.Serial, core.BigSerial: c.IsPrimaryKey = true c.IsAutoIncrement = true c.Nullable = false - return Integer + return core.Integer default: return t } @@ -84,10 +84,10 @@ func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interfac return sql, args } -func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, error) { +func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{tableName} s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, nil, err } @@ -110,11 +110,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e nStart := strings.Index(name, "(") nEnd := strings.Index(name, ")") colCreates := strings.Split(name[nStart+1:nEnd], ",") - cols := make(map[string]*Column) + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for _, colStr := range colCreates { fields := strings.Fields(strings.TrimSpace(colStr)) - col := new(Column) + col := new(core.Column) col.Indexes = make(map[string]bool) col.Nullable = true for idx, field := range fields { @@ -122,7 +122,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e col.Name = strings.Trim(field, "`[] ") continue } else if idx == 1 { - col.SQLType = SQLType{field, 0, 0} + col.SQLType = core.SQLType{field, 0, 0} } switch field { case "PRIMARY": @@ -143,11 +143,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e return colSeq, cols, nil } -func (db *sqlite3) GetTables() ([]*Table, error) { +func (db *sqlite3) GetTables() ([]*core.Table, error) { args := []interface{}{} s := "SELECT name FROM sqlite_master WHERE type='table'" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -158,9 +158,9 @@ func (db *sqlite3) GetTables() ([]*Table, error) { } defer rows.Close() - tables := make([]*Table, 0) + tables := make([]*core.Table, 0) for rows.Next() { - table := NewEmptyTable() + table := core.NewEmptyTable() err = rows.Scan(&table.Name) if err != nil { return nil, err @@ -173,10 +173,10 @@ func (db *sqlite3) GetTables() ([]*Table, error) { return tables, nil } -func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) { +func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) { args := []interface{}{tableName} s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?" - cnn, err := Open(db.DriverName(), db.DataSourceName()) + cnn, err := core.Open(db.DriverName(), db.DataSourceName()) if err != nil { return nil, err } @@ -187,7 +187,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) { } defer rows.Close() - indexes := make(map[string]*Index, 0) + indexes := make(map[string]*core.Index, 0) for rows.Next() { var sql string err = rows.Scan(&sql) @@ -199,7 +199,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) { continue } - index := new(Index) + index := new(core.Index) nNStart := strings.Index(sql, "INDEX") nNEnd := strings.Index(sql, "ON") if nNStart == -1 || nNEnd == -1 { @@ -215,9 +215,9 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) { } if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") { - index.Type = UniqueType + index.Type = core.UniqueType } else { - index.Type = IndexType + index.Type = core.IndexType } nStart := strings.Index(sql, "(") @@ -234,6 +234,6 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) { return indexes, nil } -func (db *sqlite3) Filters() []Filter { - return []Filter{&IdFilter{}} +func (db *sqlite3) Filters() []core.Filter { + return []core.Filter{&core.IdFilter{}} } diff --git a/xorm.go b/xorm.go index ccd33091..705b61a0 100644 --- a/xorm.go +++ b/xorm.go @@ -1,6 +1,7 @@ package xorm import ( + "database/sql" "errors" "fmt" "os" @@ -11,7 +12,6 @@ import ( "github.com/go-xorm/core" "github.com/go-xorm/xorm/caches" - _ "github.com/go-xorm/xorm/dialects" _ "github.com/go-xorm/xorm/drivers" ) @@ -19,6 +19,27 @@ const ( Version string = "0.4" ) +func init() { + provided_dialects := map[string]struct { + dbType core.DbType + get func() core.Dialect + }{ + "odbc": {"mssql", func() core.Dialect { return &mssql{} }}, + "mysql": {"mysql", func() core.Dialect { return &mysql{} }}, + "mymysql": {"mysql", func() core.Dialect { return &mysql{} }}, + "oci8": {"oracle", func() core.Dialect { return &oracle{} }}, + "postgres": {"postgres", func() core.Dialect { return &postgres{} }}, + "sqlite3": {"sqlite3", func() core.Dialect { return &sqlite3{} }}, + } + + for k, v := range provided_dialects { + _, err := sql.Open(string(k), "") + if err == nil { + core.RegisterDialect(v.dbType, v.get()) + } + } +} + func close(engine *Engine) { engine.Close() } From b1dfd648f25bc8048b36a8c6269e8b84d3bad940 Mon Sep 17 00:00:00 2001 From: Nash Tsai Date: Fri, 11 Apr 2014 21:31:44 +0800 Subject: [PATCH 40/41] fixed #86, increment version field after update --- session.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/session.go b/session.go index c6713ba0..c94e89aa 100644 --- a/session.go +++ b/session.go @@ -2981,6 +2981,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 var sqlStr, inSql string var inArgs []interface{} + doIncVer := false + var verValue *reflect.Value if table.Version != "" && session.Statement.checkVersion { if condition != "" { condition = fmt.Sprintf("WHERE (%v) AND %v = ?", condition, @@ -3003,12 +3005,13 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1", condition) - verValue, err := table.VersionColumn().ValueOf(bean) + verValue, err = table.VersionColumn().ValueOf(bean) if err != nil { return 0, err } condiArgs = append(condiArgs, verValue.Interface()) + doIncVer = true } else { if condition != "" { condition = "WHERE " + condition @@ -3035,6 +3038,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 res, err := session.exec(sqlStr, args...) if err != nil { return 0, err + } else if doIncVer { + verValue.SetInt(verValue.Int() + 1) } if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { From a8b9f5d8b8ed5659b85d1ffb4c54061fa5af8952 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 11 Apr 2014 23:33:56 +0800 Subject: [PATCH 41/41] bug fixed and code refactoring --- mysql_dialect.go | 3 +++ postgres_dialect.go | 19 +------------------ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/mysql_dialect.go b/mysql_dialect.go index 52a8a15e..58a30c44 100644 --- a/mysql_dialect.go +++ b/mysql_dialect.go @@ -119,10 +119,13 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column return nil, nil, err } defer cnn.Close() + rows, err := cnn.Query(s, args...) if err != nil { return nil, nil, err } + defer rows.Close() + cols := make(map[string]*core.Column) colSeq := make([]string, 0) for rows.Next() { diff --git a/postgres_dialect.go b/postgres_dialect.go index 58d39f9d..51269d53 100644 --- a/postgres_dialect.go +++ b/postgres_dialect.go @@ -276,23 +276,6 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) return indexes, nil } -// PgSeqFilter filter SQL replace ?, ? ... to $1, $2 ... -type PgSeqFilter struct { -} - -func (s *PgSeqFilter) Do(sql string, dialect core.Dialect, table *core.Table) string { - segs := strings.Split(sql, "?") - size := len(segs) - res := "" - for i, c := range segs { - if i < size-1 { - res += c + fmt.Sprintf("$%v", i+1) - } - } - res += segs[size-1] - return res -} - func (db *postgres) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &PgSeqFilter{}} + return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{"$", 1}} }