v0.1.8 union index and union unique supported
This commit is contained in:
parent
2113d5fd4c
commit
5adfc8e923
10
README.md
10
README.md
|
@ -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
|
||||
|
|
19
README_CN.md
19
README_CN.md
|
@ -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函数替代;
|
||||
|
@ -68,7 +69,12 @@ import (
|
|||
)
|
||||
engine, err = xorm.NewEngine("sqlite3", "./test.db")
|
||||
defer engine.Close()
|
||||
```
|
||||
```
|
||||
|
||||
具体连接请参考:
|
||||
Mysql:https://github.com/go-sql-driver/mysql#dsn-data-source-name
|
||||
Sqlite:
|
||||
|
||||
|
||||
1.1.默认将不会显示自动生成的SQL语句,如果要显示,则需要设置
|
||||
|
||||
|
@ -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
|
||||
|
|
67
engine.go
67
engine.go
|
@ -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
|
||||
|
|
33
session.go
33
session.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
38
statement.go
38
statement.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
19
table.go
19
table.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
7
xorm.go
7
xorm.go
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue