v0.1.8 union index and union unique supported

This commit is contained in:
Lunny Xiao 2013-07-27 12:24:38 +08:00
parent 2113d5fd4c
commit 5adfc8e923
8 changed files with 167 additions and 30 deletions

View File

@ -17,6 +17,7 @@ Drivers for Go's sql package which currently support database/sql includes:
## Changelog
* **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.
@ -304,7 +305,7 @@ Another is use field tag, field tag support the below keywords which split with
<table>
<tr>
<td>name</td><td>column name</td>
<td>name</td><td>column name, if no this name, the name is auto generated according field name and mapper rule.</td>
</tr>
<tr>
<td>pk</td><td>the field is a primary key</td>
@ -319,7 +320,10 @@ Another is use field tag, field tag support the below keywords which split with
<td>[not ]null</td><td>if column can be null value</td>
</tr>
<tr>
<td>unique</td><td>unique</td>
<td>unique or unique(uniquename)</td><td>unique or union unique as uniquename</td>
</tr>
<tr>
<td>index or index(indexname)</td><td>index or union index as indexname</td>
</tr>
<tr>
<td>extends</td><td>used in anonymous struct means mapping this struct's fields to table</td>
@ -334,7 +338,7 @@ For Example
```Go
type Userinfo struct {
Uid int `xorm:"id pk not null autoincr"`
Username string
Username string `xorm:"unique"`
Departname string
Alias string `xorm:"-"`
Created time.Time

View File

@ -16,6 +16,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
## 更新日志
* **v0.1.8** : 新增联合index联合unique支持请查看[映射规则](#mapping)。
* **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函数替代
@ -70,6 +71,11 @@ engine, err = xorm.NewEngine("sqlite3", "./test.db")
defer engine.Close()
```
具体连接请参考:
Mysqlhttps://github.com/go-sql-driver/mysql#dsn-data-source-name
Sqlite
1.1.默认将不会显示自动生成的SQL语句如果要显示则需要设置
```Go
@ -305,10 +311,10 @@ UserInfo中的成员UserName将会自动对应名为user_name的字段。
<table>
<tr>
<td>name</td><td>当前field对应的字段的名称可选</td>
<td>name</td><td>当前field对应的字段的名称可选如不写则自动根据field名字和转换规则命名</td>
</tr>
<tr>
<td>pk</td><td>是否是Primary Key</td>
<td>pk</td><td>是否是Primary Key当前仅支持int64类型</td>
</tr>
<tr>
<td>int(11)/varchar(50)/text/date/datetime/blob/decimal(26,2)</td><td>字段类型</td>
@ -320,7 +326,10 @@ UserInfo中的成员UserName将会自动对应名为user_name的字段。
<td>[not ]null</td><td>是否可以为空</td>
</tr>
<tr>
<td>unique</td><td>是否是唯一</td>
<td>unique或unique(uniquename)</td><td>是否是唯一,如不加括号则该字段不允许重复,如加上括号,则括号中为联合唯一的名字,此时可以有另外一个或多个字段有相同的写法</td>
</tr>
<tr>
<td>index或index(indexname)</td><td>是否是索引,如不加括号则该字段自身为索引,如加上括号,则括号中为联合索引的名字,此时可以有另外一个或多个字段有相同的写法</td>
</tr>
<tr>
<td>extends</td><td>应用于一个匿名结构体之上,表示此匿名结构体的成员也映射到数据库中</td>
@ -334,7 +343,7 @@ UserInfo中的成员UserName将会自动对应名为user_name的字段。
```Go
type Userinfo struct {
Uid int `xorm:"id pk not null autoincr"`
Username string
Username string `xorm:"unique"`
Departname string
Alias string `xorm:"-"`
Created time.Time

View File

@ -116,6 +116,16 @@ func (engine *Engine) Id(id int64) *Session {
return session.Id(id)
}
func (engine *Engine) Charset(charset string) *Session {
session := engine.NewSession()
return session.Charset(charset)
}
func (engine *Engine) StoreEngine(storeEngine string) *Session {
session := engine.NewSession()
return session.StoreEngine(storeEngine)
}
func (engine *Engine) In(column string, args ...interface{}) *Session {
session := engine.NewSession()
return session.In(column, args...)
@ -170,7 +180,8 @@ func (engine *Engine) AutoMap(bean interface{}) *Table {
}
func (engine *Engine) MapType(t reflect.Type) *Table {
table := &Table{Name: engine.Mapper.Obj2Table(t.Name()), Type: t}
table := &Table{Name: engine.Mapper.Obj2Table(t.Name()), Type: t,
Indexes: map[string][]string{}, Uniques: map[string][]string{}}
table.Columns = make(map[string]Column)
for i := 0; i < t.NumField(); i++ {
@ -227,23 +238,43 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
col.Length, _ = strconv.Atoi(lens)
}
case strings.HasPrefix(k, "varchar"):
col.SQLType = Varchar
lens := k[len("varchar")+1 : len(k)-1]
col.Length, _ = strconv.Atoi(lens)
if k == "varchar" {
col.SQLType = Varchar
col.Length = Varchar.DefaultLength
col.Length2 = Varchar.DefaultLength2
} else {
col.SQLType = Varchar
lens := k[len("varchar")+1 : len(k)-1]
col.Length, _ = strconv.Atoi(lens)
}
case strings.HasPrefix(k, "decimal"):
col.SQLType = Decimal
lens := k[len("decimal")+1 : len(k)-1]
twolen := strings.Split(lens, ",")
col.Length, _ = strconv.Atoi(twolen[0])
col.Length2, _ = strconv.Atoi(twolen[1])
case strings.HasPrefix(k, "index"):
if k == "index" {
col.IndexName = ""
col.IndexType = SINGLEINDEX
} else {
col.IndexName = k[len("index")+1 : len(k)-1]
col.IndexType = UNIONINDEX
}
case strings.HasPrefix(k, "unique"):
if k == "unique" {
col.UniqueName = ""
col.UniqueType = SINGLEUNIQUE
} else {
col.UniqueName = k[len("unique")+1 : len(k)-1]
col.UniqueType = UNIONUNIQUE
}
case k == "date":
col.SQLType = Date
case k == "datetime":
col.SQLType = DateTime
case k == "timestamp":
col.SQLType = TimeStamp
case k == "unique":
col.IsUnique = true
case k == "not":
default:
if k != col.Default {
@ -265,6 +296,28 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
if col.Name == "" {
col.Name = engine.Mapper.Obj2Table(t.Field(i).Name)
}
if col.IndexType == SINGLEINDEX {
col.IndexName = col.Name
table.Indexes[col.IndexName] = []string{col.Name}
} else if col.IndexType == UNIONINDEX {
if unionIdxes, ok := table.Indexes[col.IndexName]; ok {
table.Indexes[col.IndexName] = append(unionIdxes, col.Name)
} else {
table.Indexes[col.IndexName] = []string{col.Name}
}
}
if col.UniqueType == SINGLEUNIQUE {
col.UniqueName = col.Name
table.Uniques[col.UniqueName] = []string{col.Name}
} else if col.UniqueType == UNIONUNIQUE {
if unionUniques, ok := table.Uniques[col.UniqueName]; ok {
table.Uniques[col.UniqueName] = append(unionUniques, col.Name)
} else {
table.Uniques[col.UniqueName] = []string{col.Name}
}
}
if col.IsPrimaryKey {
table.PrimaryKey = col.Name
}
@ -272,7 +325,7 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
} else {
sqlType := Type2SQLType(fieldType)
col = Column{engine.Mapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", false, false, false, TWOSIDES}
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", NONEUNIQUE, "", NONEINDEX, "", false, false, TWOSIDES}
if col.Name == "id" {
col.IsPrimaryKey = true

View File

@ -79,6 +79,16 @@ func (session *Session) OrderBy(order string) *Session {
return session
}
func (session *Session) StoreEngine(storeEngine string) *Session {
session.Statement.StoreEngine = storeEngine
return session
}
func (session *Session) Charset(charset string) *Session {
session.Statement.Charset = charset
return session
}
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
if len(trueOrFalse) >= 1 {
session.Statement.UseCascade = trueOrFalse[0]
@ -319,12 +329,33 @@ func (session *Session) Exec(sql string, args ...interface{}) (sql.Result, error
return session.Tx.Exec(sql, args...)
}
// this function create a table according a bean
func (session *Session) CreateTable(bean interface{}) error {
statement := session.Statement
defer statement.Init()
statement.RefTable = session.Engine.AutoMap(bean)
sql := statement.genCreateSQL()
_, err := session.Exec(sql)
res, err := session.Exec(sql)
if err != nil {
return err
}
affected, err := res.RowsAffected()
if err != nil {
return err
}
if affected > 0 {
sql = statement.genIndexSQL()
if len(sql) > 0 {
_, err = session.Exec(sql)
}
}
if err == nil && affected > 0 {
sql = statement.genUniqueSQL()
if len(sql) > 0 {
_, err = session.Exec(sql)
}
}
return err
}

View File

@ -31,6 +31,9 @@ type Statement struct {
RawSQL string
RawParams []interface{}
UseCascade bool
UseAutoJoin bool
StoreEngine string
Charset string
BeanArgs []interface{}
}
@ -142,7 +145,7 @@ func (statement *Statement) Id(id int64) {
}
func (statement *Statement) In(column string, args ...interface{}) {
inStr := fmt.Sprintf("%v in (%v)", column, strings.Join(MakeArray("?", len(args)), ","))
inStr := fmt.Sprintf("%v IN (%v)", column, strings.Join(MakeArray("?", len(args)), ","))
if statement.WhereStr == "" {
statement.WhereStr = inStr
statement.Params = args
@ -199,9 +202,9 @@ func (statement *Statement) genColumnStr(col *Column) string {
sql += "NOT NULL "
}
if col.IsUnique {
sql += "Unique "
}
/*if col.UniqueType == SINGLEUNIQUE {
sql += "UNIQUE "
}*/
if col.Default != "" {
sql += "DEFAULT " + col.Default + " "
@ -227,7 +230,32 @@ func (statement *Statement) genCreateSQL() string {
sql = strings.TrimSpace(sql)
sql += ", "
}
sql = sql[:len(sql)-2] + ");"
sql = sql[:len(sql)-2] + ")"
if statement.StoreEngine != "" {
sql += " ENGINE=" + statement.StoreEngine
}
if statement.Charset != "" {
sql += " DEFAULT CHARSET " + statement.Charset
}
sql += ";"
return sql
}
func (statement *Statement) genIndexSQL() string {
var sql string = ""
for indexName, cols := range statement.RefTable.Indexes {
sql += fmt.Sprintf("CREATE INDEX IF NOT EXISTS IDX_%v_%v ON %v (%v);", statement.TableName(), indexName,
statement.TableName(), strings.Join(cols, ","))
}
return sql
}
func (statement *Statement) genUniqueSQL() string {
var sql string = ""
for indexName, cols := range statement.RefTable.Uniques {
sql += fmt.Sprintf("CREATE UNIQUE INDEX IF NOT EXISTS UQE_%v_%v ON %v (%v);", statement.TableName(), indexName,
statement.TableName(), strings.Join(cols, ","))
}
return sql
}

View File

@ -77,6 +77,18 @@ const (
ONLYFROMDB
)
const (
NONEINDEX = iota
SINGLEINDEX
UNIONINDEX
)
const (
NONEUNIQUE = iota
SINGLEUNIQUE
UNIONUNIQUE
)
type Column struct {
Name string
FieldName string
@ -85,7 +97,10 @@ type Column struct {
Length2 int
Nullable bool
Default string
IsUnique bool
UniqueType int
UniqueName string
IndexType int
IndexName string
IsPrimaryKey bool
IsAutoIncrement bool
MapType int
@ -95,6 +110,8 @@ type Table struct {
Name string
Type reflect.Type
Columns map[string]Column
Indexes map[string][]string
Uniques map[string][]string
PrimaryKey string
}

View File

@ -23,8 +23,8 @@ CREATE TABLE `userdeatail` (
*/
type Userinfo struct {
Uid int64 `xorm:"id pk not null autoincr"`
Username string
Uid int64 `xorm:"id pk not null autoincr"`
Username string `xorm:"unique"`
Departname string
Alias string `xorm:"-"`
Created time.Time

View File

@ -17,7 +17,7 @@ import (
)
const (
version string = "0.1.6"
version string = "0.1.8"
)
func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
@ -26,16 +26,11 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
engine.Tables = make(map[reflect.Type]*Table)
engine.mutex = &sync.Mutex{}
//engine.InsertMany = true
engine.TagIdentifier = "xorm"
//engine.QuoteIdentifier = "`"
if driverName == SQLITE {
engine.Dialect = &sqlite3{}
//engine.AutoIncrement = "AUTOINCREMENT"
//engine.Pool = NoneConnectPool{}
} else if driverName == MYSQL {
engine.Dialect = &mysql{}
//engine.AutoIncrement = "AUTO_INCREMENT"
} else {
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
}