diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 2fc373a7..cac249c6 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -65,11 +65,8 @@ defer engine.Close() 一般如果只针对一个数据库进行操作,只需要创建一个Engine即可。Engine支持在多GoRutine下使用。 xorm当前支持五种驱动四个数据库如下: -<<<<<<< HEAD -======= * Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL) ->>>>>>> master * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) @@ -124,15 +121,9 @@ engine.SetMapper(SameMapper{}) 同时需要注意的是: -<<<<<<< HEAD * 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 * 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: -======= -* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 -* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: - ->>>>>>> master ```Go engine.SetTableMapper(SameMapper{}) engine.SetColumnMapper(SnakeMapper{}) @@ -142,12 +133,10 @@ engine.SetColumnMapper(SnakeMapper{}) ### 2.2.前缀映射,后缀映射和缓存映射 * 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 + * 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 -<<<<<<< HEAD -* -======= + * 通过`eneing.NewCacheMapper(SnakeMapper{})`可以组合其它的映射规则,起到在内存中缓存曾经映射过的命名映射。 ->>>>>>> master ### 2.3.使用Table和Tag改变名称映射 @@ -598,21 +587,12 @@ affected, err := engine.Id(id).Update(user) 这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择: -<<<<<<< HEAD 1. 通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 -======= -* 1.通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 ->>>>>>> master - ```Go affected, err := engine.Id(id).Cols("age").Update(&user) ``` -<<<<<<< HEAD 2. 通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 -======= -* 2.通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 ->>>>>>> master ```Go affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0}) diff --git a/docs/QuickStartEn.md b/docs/QuickStartEn.md index a8dce7cc..aa9baa2e 100644 --- a/docs/QuickStartEn.md +++ b/docs/QuickStartEn.md @@ -70,6 +70,8 @@ xorm supports four drivers now: * Postgres: [github.com/lib/pq](https://github.com/lib/pq) +* MsSql: [github.com/lunny/godbc](https://githubcom/lunny/godbc) + NewEngine's parameters are the same as `sql.Open`. So you should read the drivers' document for parameters' usage. After engine created, you can do some settings. @@ -100,7 +102,7 @@ engine.Logger = f ## 2.Define struct -xorm map a struct to a database table, the rule is below. +xorm maps a struct to a database table, the rule is below. ### 2.1.name mapping rule @@ -110,13 +112,13 @@ use xorm.IMapper interface to implement. There are two IMapper implemented: `Sna SnakeMapper is the default. ```Go -engine.Mapper = SameMapper{} +engine.SetMapper(SameMapper{}) ``` -同时需要注意的是: +And you should notice: -* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 -* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如: +* If you want to use other mapping rule, implement IMapper +* Tables's mapping rule could be different from Columns': ```Go engine.SetTableMapper(SameMapper{}) @@ -124,7 +126,7 @@ engine.SetColumnMapper(SnakeMapper{}) ``` -### 2.2.前缀映射规则,后缀映射规则和缓存映射规则 +### 2.2.Prefix mapping, Suffix Mapping and Cache Mapping * 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 * 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。 @@ -133,14 +135,15 @@ engine.SetColumnMapper(SnakeMapper{}) 当然,如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。 -### 2.3.使用Table和Tag改变名称映射 +### 2.3.Tag mapping 如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。 通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。 -### 2.4.Column属性定义 +### 2.4.Column defenition + 我们在field对应的Tag中对Column的一些属性进行定义,定义的方法基本和我们写SQL定义表结构类似,比如: ``` @@ -150,37 +153,37 @@ type User struct { } ``` -对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。 +For different DBMS, data types对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。 具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写: - + - + - + - + - + - + - + @@ -198,7 +201,7 @@ type User struct { - +
name当前field对应的字段的名称,可选,如不写,则自动根据field名字和转换规则命名name or 'name'Column Name, optional
pk是否是Primary Key,当前仅支持int64类型pkIf column is Primary Key
当前支持30多种字段类型,详情参见 [字段类型](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)字段类型
autoincr是否是自增autoincrIf autoincrement column
[not ]null是否可以为空[not ]null | notnullif column could be blank
unique或unique(uniquename)是否是唯一,如不加括号则该字段不允许重复;如加上括号,则括号中为联合唯一索引的名字,此时如果有另外一个或多个字段和本unique的uniquename相同,则这些uniquename相同的字段组成联合唯一索引unique/unique(uniquename)是否是唯一,如不加括号则该字段不允许重复;如加上括号,则括号中为联合唯一索引的名字,此时如果有另外一个或多个字段和本unique的uniquename相同,则这些uniquename相同的字段组成联合唯一索引
index或index(indexname)是否是索引,如不加括号则该字段自身为索引,如加上括号,则括号中为联合索引的名字,此时如果有另外一个或多个字段和本index的indexname相同,则这些indexname相同的字段组成联合索引index/index(indexname)是否是索引,如不加括号则该字段自身为索引,如加上括号,则括号中为联合索引的名字,此时如果有另外一个或多个字段和本index的indexname相同,则这些indexname相同的字段组成联合索引
extends应用于一个匿名结构体之上,表示此匿名结构体的成员也映射到数据库中
-这个Field将不进行字段映射-This field will not be mapping
->这个Field将只写入到数据库而不从数据库读取versionThis field will be filled 1 on insert and autoincrement on update
default 0设置默认值,紧跟的内容如果是Varchar等需要加上单引号default 0 | default 'name'column default value
@@ -224,13 +227,13 @@ type Conversion interface { xorm提供了一些动态获取和修改表结构的方法。对于一般的应用,很少动态修改表结构,则只需调用Sync()同步下表结构即可。 -## 3.1 获取数据库信息 +## 3.1 retrieve database meta info * DBMetas() xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到所有的表的信息 -## 3.2.表操作 +## 3.2.directly table operation * CreateTables() 创建表使用`engine.CreateTables()`,参数为一个或多个空的对应Struct的指针。同时可用的方法有Charset()和StoreEngine(),如果对应的数据库支持,这两个方法可以在创建表时指定表的字符编码和使用的引擎。当前仅支持Mysql数据库。 @@ -245,7 +248,7 @@ xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到 删除表使用`engine.DropTables()`,参数为一个或多个空的对应Struct的指针或者表的名字。如果为string传入,则只删除对应的表,如果传入的为Struct,则删除表的同时还会删除对应的索引。 -## 3.3.创建索引和唯一索引 +## 3.3.create indexes and uniques * CreateIndexes 根据struct中的tag来创建索引 diff --git a/engine.go b/engine.go index 0ce4c8f0..7aa44b1e 100644 --- a/engine.go +++ b/engine.go @@ -88,14 +88,8 @@ func (engine *Engine) AutoIncrStr() string { return engine.dialect.AutoIncrStr() } -// Set engine's pool, the pool default is Go's standard library's connection pool. -/*func (engine *Engine) SetPool(pool IConnectPool) error { - engine.Pool = pool - return engine.Pool.Init(engine) -}*/ - -// SetMaxConns is only available for go 1.2+ -func (engine *Engine) SetMaxConns(conns int) { +// SetMaxOpenConns is only available for go 1.2+ +func (engine *Engine) SetMaxOpenConns(conns int) { engine.db.SetMaxOpenConns(conns) } @@ -139,6 +133,10 @@ func (engine *Engine) DB() *core.DB { return engine.db } +func (engine *Engine) Dialect() core.Dialect { + return engine.dialect +} + // New a session func (engine *Engine) NewSession() *Session { session := &Session{Engine: engine} diff --git a/examples/cache.go b/examples/cache.go index c5d50273..0fc71a08 100644 --- a/examples/cache.go +++ b/examples/cache.go @@ -3,9 +3,9 @@ package main import ( "fmt" "os" + "time" "github.com/go-xorm/xorm" - "github.com/go-xorm/xorm/caches" _ "github.com/mattn/go-sqlite3" ) @@ -24,7 +24,7 @@ func main() { return } Orm.ShowSQL = true - cacher := xorm.NewLRUCacher(caches.NewMemoryStore(), 1000) + cacher := xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) Orm.SetDefaultCacher(cacher) err = Orm.CreateTables(&User{}) diff --git a/examples/cachegoroutine.go b/examples/cachegoroutine.go index 925a16ca..0e50f5ad 100644 --- a/examples/cachegoroutine.go +++ b/examples/cachegoroutine.go @@ -2,10 +2,12 @@ package main import ( "fmt" + "os" + "time" + _ "github.com/go-sql-driver/mysql" "github.com/go-xorm/xorm" _ "github.com/mattn/go-sqlite3" - "os" ) type User struct { @@ -84,7 +86,7 @@ func main() { return } engine.ShowSQL = true - cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) + cacher := xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) engine.SetDefaultCacher(cacher) fmt.Println(engine) test(engine) @@ -94,7 +96,7 @@ func main() { fmt.Println("-----start mysql go routines-----") engine, err = mysqlEngine() engine.ShowSQL = true - cacher = xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) + cacher = xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) engine.SetDefaultCacher(cacher) if err != nil { fmt.Println(err) diff --git a/examples/maxconnect.go b/examples/maxconnect.go index 8ec82d2a..e8446cfa 100644 --- a/examples/maxconnect.go +++ b/examples/maxconnect.go @@ -34,7 +34,7 @@ func test(engine *xorm.Engine) { } engine.ShowSQL = true - engine.Pool.SetMaxConns(5) + engine.SetMaxOpenConns(5) size := 1000 queue := make(chan int, size) diff --git a/examples/pool.go b/examples/pool.go deleted file mode 100644 index 7511bb6c..00000000 --- a/examples/pool.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -func main() { - f := "pool.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - err = Orm.SetPool(xorm.NewSimpleConnectPool()) - if err != nil { - fmt.Println(err) - return - } - - Orm.ShowSQL = true - err = Orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - for i := 0; i < 10; i++ { - _, err = Orm.Get(&User{}) - if err != nil { - fmt.Println(err) - break - } - - } -} diff --git a/examples/sync.go b/examples/sync.go index f26026aa..ad28ad80 100644 --- a/examples/sync.go +++ b/examples/sync.go @@ -2,9 +2,10 @@ package main import ( "fmt" - _ "github.com/bylevel/pq" + _ "github.com/go-sql-driver/mysql" "github.com/go-xorm/xorm" + _ "github.com/lib/pq" _ "github.com/mattn/go-sqlite3" ) diff --git a/session.go b/session.go index 231f18c5..c67c46b1 100644 --- a/session.go +++ b/session.go @@ -1351,10 +1351,10 @@ func (session *Session) addIndex(tableName, idxName string) error { if session.IsAutoClose { defer session.Close() } - //fmt.Println(idxName) - cols := session.Statement.RefTable.Indexes[idxName].Cols - sqlStr, args := session.Statement.genAddIndexStr(indexName(tableName, idxName), cols) - _, err = session.exec(sqlStr, args...) + index := session.Statement.RefTable.Indexes[idxName] + sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index) + //genAddIndexStr(indexName(tableName, idxName), cols) + _, err = session.exec(sqlStr) return err } @@ -1368,9 +1368,9 @@ func (session *Session) addUnique(tableName, uqeName string) error { defer session.Close() } //fmt.Println(uqeName, session.Statement.RefTable.Uniques) - cols := session.Statement.RefTable.Indexes[uqeName].Cols - sqlStr, args := session.Statement.genAddUniqueStr(uniqueName(tableName, uqeName), cols) - _, err = session.exec(sqlStr, args...) + index := session.Statement.RefTable.Indexes[uqeName] + sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index) + _, err = session.exec(sqlStr) return err } diff --git a/statement.go b/statement.go index 9330a14d..b6c1152c 100644 --- a/statement.go +++ b/statement.go @@ -99,7 +99,8 @@ func (statement *Statement) Where(querystring string, args ...interface{}) *Stat // add Where & and statment func (statement *Statement) And(querystring string, args ...interface{}) *Statement { if statement.WhereStr != "" { - statement.WhereStr = fmt.Sprintf("(%v) AND (%v)", statement.WhereStr, querystring) + statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr, + statement.Engine.dialect.AndStr(), querystring) } else { statement.WhereStr = querystring } @@ -110,7 +111,8 @@ func (statement *Statement) And(querystring string, args ...interface{}) *Statem // add Where & Or statment func (statement *Statement) Or(querystring string, args ...interface{}) *Statement { if statement.WhereStr != "" { - statement.WhereStr = fmt.Sprintf("(%v) OR (%v)", statement.WhereStr, querystring) + statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr, + statement.Engine.dialect.OrStr(), querystring) } else { statement.WhereStr = querystring } @@ -451,24 +453,10 @@ func (statement *Statement) Id(id interface{}) *Statement { statement.IdParam = &pk } default: - // TODO treat as int primitve for now, need to handle type check + // TODO: treat as int primitve for now, need to handle type check? statement.IdParam = &core.PK{id} - - // !nashtsai! REVIEW although it will be user's mistake if called Id() twice with - // different value and Id should be PK's field name, however, at this stage probably - // can't tell which table is gonna be used - // if statement.WhereStr == "" { - // statement.WhereStr = "(id)=?" - // statement.Params = []interface{}{id} - // } else { - // // TODO what if id param has already passed - // statement.WhereStr = statement.WhereStr + " AND (id)=?" - // statement.Params = append(statement.Params, id) - // } } - // !nashtsai! perhaps no need to validate pk values' type just let sql complaint happen - return statement } @@ -516,14 +504,14 @@ func (statement *Statement) genInSql() (string, []interface{}) { if len(statement.inColumns) == 1 { return inStrs[0], args } - return fmt.Sprintf("(%v)", strings.Join(inStrs, " AND ")), args + return fmt.Sprintf("(%v)", strings.Join(inStrs, " "+statement.Engine.dialect.AndStr()+" ")), args } func (statement *Statement) attachInSql() { inSql, inArgs := statement.genInSql() if len(inSql) > 0 { if statement.ConditionStr != "" { - statement.ConditionStr += " AND " + statement.ConditionStr += " " + statement.Engine.dialect.AndStr() + " " } statement.ConditionStr += inSql statement.Params = append(statement.Params, inArgs...) @@ -696,11 +684,9 @@ func uniqueName(tableName, uqeName string) string { func (s *Statement) genUniqueSQL() []string { var sqls []string = make([]string, 0) tbName := s.TableName() - quote := s.Engine.Quote - for idxName, unique := range s.RefTable.Indexes { - if unique.Type == core.UniqueType { - sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uniqueName(tbName, idxName)), - quote(tbName), quote(strings.Join(unique.Cols, quote(",")))) + for _, index := range s.RefTable.Indexes { + if index.Type == core.UniqueType { + sql := s.Engine.dialect.CreateIndexSql(tbName, index) sqls = append(sqls, sql) } } @@ -737,7 +723,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) false, true, statement.allUseBool, statement.useAllCols, statement.mustColumnMap) - statement.ConditionStr = strings.Join(colNames, " AND ") + statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ") statement.BeanArgs = args var columnStr string = statement.ColumnStr @@ -755,7 +741,7 @@ func (s *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) { return sql, []interface{}{} } -func (s *Statement) genAddIndexStr(idxName string, cols []string) (string, []interface{}) { +/*func (s *Statement) genAddIndexStr(idxName string, cols []string) (string, []interface{}) { quote := s.Engine.Quote colstr := quote(strings.Join(cols, quote(", "))) sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(idxName), quote(s.TableName()), colstr) @@ -767,7 +753,7 @@ func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []in colstr := quote(strings.Join(cols, quote(", "))) sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uqeName), quote(s.TableName()), colstr) return sql, []interface{}{} -} +}*/ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}) { table := statement.Engine.autoMap(bean)