Merge branch 'master' of https://github.com/go-xorm/xorm
Conflicts: session.go
This commit is contained in:
commit
7d79bd259b
146
README.md
146
README.md
|
@ -11,7 +11,7 @@ Xorm is a simple and powerful ORM for Go.
|
||||||
* Struct <-> Table Mapping Support
|
* Struct <-> Table Mapping Support
|
||||||
|
|
||||||
* Chainable APIs
|
* Chainable APIs
|
||||||
|
|
||||||
* Transaction Support
|
* Transaction Support
|
||||||
|
|
||||||
* Both ORM and raw SQL operation Support
|
* Both ORM and raw SQL operation Support
|
||||||
|
@ -72,7 +72,7 @@ Drivers for Go's sql package which currently support database/sql includes:
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
If you have [gopm](https://github.com/gpmgo/gopm) installed,
|
If you have [gopm](https://github.com/gpmgo/gopm) installed,
|
||||||
|
|
||||||
gopm get github.com/go-xorm/xorm
|
gopm get github.com/go-xorm/xorm
|
||||||
|
|
||||||
|
@ -88,6 +88,148 @@ Or
|
||||||
|
|
||||||
* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
|
* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
* Create Engine
|
||||||
|
|
||||||
|
```Go
|
||||||
|
engine, err := xorm.NewEngine(driverName, dataSourceName)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Define a struct and Sync2 table struct to database
|
||||||
|
|
||||||
|
```Go
|
||||||
|
type User struct {
|
||||||
|
Id int64
|
||||||
|
Name string
|
||||||
|
Salt string
|
||||||
|
Age int
|
||||||
|
Passwd string `xorm:"varchar(200)"`
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
|
Updated time.Time `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := engine.Sync2(new(User))
|
||||||
|
```
|
||||||
|
|
||||||
|
* Query a SQL string, the returned results is []map[string][]byte
|
||||||
|
|
||||||
|
```Go
|
||||||
|
results, err := engine.Query("select * from user")
|
||||||
|
```
|
||||||
|
|
||||||
|
* Execute a SQL string, the returned results
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Insert one or multipe records to database
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Insert(&user)
|
||||||
|
// INSERT INTO struct () values ()
|
||||||
|
affected, err := engine.Insert(&user1, &user2)
|
||||||
|
// INSERT INTO struct1 () values ()
|
||||||
|
// INSERT INTO struct2 () values ()
|
||||||
|
affected, err := engine.Insert(&users)
|
||||||
|
// INSERT INTO struct () values (),(),()
|
||||||
|
affected, err := engine.Insert(&user1, &users)
|
||||||
|
// INSERT INTO struct1 () values ()
|
||||||
|
// INSERT INTO struct2 () values (),(),()
|
||||||
|
```
|
||||||
|
|
||||||
|
* Query one record from database
|
||||||
|
|
||||||
|
```Go
|
||||||
|
has, err := engine.Get(&user)
|
||||||
|
// SELECT * FROM user LIMIT 1
|
||||||
|
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
|
||||||
|
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
|
||||||
|
```
|
||||||
|
|
||||||
|
* Query multiple records from database, also you can use join and extends
|
||||||
|
|
||||||
|
```Go
|
||||||
|
var users []User
|
||||||
|
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
|
||||||
|
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
|
||||||
|
|
||||||
|
type Detail struct {
|
||||||
|
Id int64
|
||||||
|
UserId int64 `xorm:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserDetail struct {
|
||||||
|
User `xorm:"extends"`
|
||||||
|
Detail `xorm:"extends"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var users []UserDetail
|
||||||
|
err := engine.Table("user").Select("user.*, detail.*")
|
||||||
|
Join("INNER", "detail", "detail.user_id = user.id").
|
||||||
|
Where("user.name = ?", name).Limit(10, 0).
|
||||||
|
Find(&users)
|
||||||
|
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
|
||||||
|
```
|
||||||
|
|
||||||
|
* Query multiple records and record by record handle, there two methods Iterate and Rows
|
||||||
|
|
||||||
|
```Go
|
||||||
|
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||||
|
user := bean.(*User)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
// SELECT * FROM user
|
||||||
|
|
||||||
|
rows, err := engine.Rows(&User{Name:name})
|
||||||
|
// SELECT * FROM user
|
||||||
|
defer rows.Close()
|
||||||
|
bean := new(Struct)
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(bean)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Update one or more records, default will update non-empty and non-zero fields except to use Cols, AllCols and etc.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Id(1).Update(&user)
|
||||||
|
// UPDATE user SET ... Where id = ?
|
||||||
|
|
||||||
|
affected, err := engine.Update(&user, &User{Name:name})
|
||||||
|
// UPDATE user SET ... Where name = ?
|
||||||
|
|
||||||
|
var ids = []int64{1, 2, 3}
|
||||||
|
affected, err := engine.In(ids).Update(&user)
|
||||||
|
// UPDATE user SET ... Where id IN (?, ?, ?)
|
||||||
|
|
||||||
|
// force update indicated columns by Cols
|
||||||
|
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||||
|
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||||
|
|
||||||
|
// force NOT update indicated columns by Omit
|
||||||
|
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||||
|
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||||
|
|
||||||
|
affected, err := engine.Id(1).AllCols().Update(&user)
|
||||||
|
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
|
||||||
|
```
|
||||||
|
|
||||||
|
* Delete one or more records, Delete MUST has conditon
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Where(...).Delete(&user)
|
||||||
|
// DELETE FROM user Where ...
|
||||||
|
```
|
||||||
|
|
||||||
|
* Count records
|
||||||
|
|
||||||
|
```Go
|
||||||
|
counts, err := engine.Count(&user)
|
||||||
|
// SELECT count(*) AS total FROM user
|
||||||
|
```
|
||||||
|
|
||||||
# Cases
|
# Cases
|
||||||
|
|
||||||
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
|
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
|
||||||
|
|
151
README_CN.md
151
README_CN.md
|
@ -20,7 +20,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
|
|
||||||
* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
|
* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
|
||||||
|
|
||||||
* 支持级联加载Struct
|
* 支持级联加载Struct
|
||||||
|
|
||||||
* 支持缓存
|
* 支持缓存
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
* sql.NullString支持
|
* sql.NullString支持
|
||||||
* ForUpdate 支持
|
* ForUpdate 支持
|
||||||
* bug修正
|
* bug修正
|
||||||
|
|
||||||
* **v0.4.3**
|
* **v0.4.3**
|
||||||
* Json 字段类型支持
|
* Json 字段类型支持
|
||||||
* oracle实验性支持
|
* oracle实验性支持
|
||||||
|
@ -68,10 +68,10 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
|
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
|
||||||
|
|
||||||
gopm get github.com/go-xorm/xorm
|
gopm get github.com/go-xorm/xorm
|
||||||
|
|
||||||
或者您也可以使用go工具进行安装:
|
或者您也可以使用go工具进行安装:
|
||||||
|
|
||||||
go get github.com/go-xorm/xorm
|
go get github.com/go-xorm/xorm
|
||||||
|
@ -84,8 +84,149 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
|
|
||||||
* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
|
* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
|
# 快速开始
|
||||||
|
|
||||||
## 案例
|
* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同
|
||||||
|
|
||||||
|
```Go
|
||||||
|
engine, err := xorm.NewEngine(driverName, dataSourceName)
|
||||||
|
```
|
||||||
|
|
||||||
|
* 定义一个和表同步的结构体,并且自动同步结构体到数据库
|
||||||
|
|
||||||
|
```Go
|
||||||
|
type User struct {
|
||||||
|
Id int64
|
||||||
|
Name string
|
||||||
|
Salt string
|
||||||
|
Age int
|
||||||
|
Passwd string `xorm:"varchar(200)"`
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
|
Updated time.Time `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := engine.Sync2(new(User))
|
||||||
|
```
|
||||||
|
|
||||||
|
* 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte
|
||||||
|
|
||||||
|
```Go
|
||||||
|
results, err := engine.Query("select * from user")
|
||||||
|
```
|
||||||
|
|
||||||
|
* 执行一个SQL语句
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
|
||||||
|
```
|
||||||
|
|
||||||
|
* 插入一条或者多条记录
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Insert(&user)
|
||||||
|
// INSERT INTO struct () values ()
|
||||||
|
affected, err := engine.Insert(&user1, &user2)
|
||||||
|
// INSERT INTO struct1 () values ()
|
||||||
|
// INSERT INTO struct2 () values ()
|
||||||
|
affected, err := engine.Insert(&users)
|
||||||
|
// INSERT INTO struct () values (),(),()
|
||||||
|
affected, err := engine.Insert(&user1, &users)
|
||||||
|
// INSERT INTO struct1 () values ()
|
||||||
|
// INSERT INTO struct2 () values (),(),()
|
||||||
|
```
|
||||||
|
|
||||||
|
* 查询单条记录
|
||||||
|
|
||||||
|
```Go
|
||||||
|
has, err := engine.Get(&user)
|
||||||
|
// SELECT * FROM user LIMIT 1
|
||||||
|
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
|
||||||
|
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
|
||||||
|
```
|
||||||
|
|
||||||
|
* 查询多条记录,当然可以使用Join和extends来组合使用
|
||||||
|
|
||||||
|
```Go
|
||||||
|
var users []User
|
||||||
|
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
|
||||||
|
// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
|
||||||
|
|
||||||
|
type Detail struct {
|
||||||
|
Id int64
|
||||||
|
UserId int64 `xorm:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserDetail struct {
|
||||||
|
User `xorm:"extends"`
|
||||||
|
Detail `xorm:"extends"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var users []UserDetail
|
||||||
|
err := engine.Table("user").Select("user.*, detail.*")
|
||||||
|
Join("INNER", "detail", "detail.user_id = user.id").
|
||||||
|
Where("user.name = ?", name).Limit(10, 0).
|
||||||
|
Find(&users)
|
||||||
|
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
|
||||||
|
```
|
||||||
|
|
||||||
|
* 根据条件遍历数据库,可以有两种方式: Iterate and Rows
|
||||||
|
|
||||||
|
```Go
|
||||||
|
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
|
||||||
|
user := bean.(*User)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
// SELECT * FROM user
|
||||||
|
|
||||||
|
rows, err := engine.Rows(&User{Name:name})
|
||||||
|
// SELECT * FROM user
|
||||||
|
defer rows.Close()
|
||||||
|
bean := new(Struct)
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(bean)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Id(1).Update(&user)
|
||||||
|
// UPDATE user SET ... Where id = ?
|
||||||
|
|
||||||
|
affected, err := engine.Update(&user, &User{Name:name})
|
||||||
|
// UPDATE user SET ... Where name = ?
|
||||||
|
|
||||||
|
var ids = []int64{1, 2, 3}
|
||||||
|
affected, err := engine.In(ids).Update(&user)
|
||||||
|
// UPDATE user SET ... Where id IN (?, ?, ?)
|
||||||
|
|
||||||
|
// force update indicated columns by Cols
|
||||||
|
affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
|
||||||
|
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||||
|
|
||||||
|
// force NOT update indicated columns by Omit
|
||||||
|
affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
|
||||||
|
// UPDATE user SET age = ?, updated=? Where id = ?
|
||||||
|
|
||||||
|
affected, err := engine.Id(1).AllCols().Update(&user)
|
||||||
|
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
|
||||||
|
```
|
||||||
|
|
||||||
|
* 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
|
||||||
|
|
||||||
|
```Go
|
||||||
|
affected, err := engine.Where(...).Delete(&user)
|
||||||
|
// DELETE FROM user Where ...
|
||||||
|
```
|
||||||
|
|
||||||
|
* 获取记录条数
|
||||||
|
|
||||||
|
```Go
|
||||||
|
counts, err := engine.Count(&user)
|
||||||
|
// SELECT count(*) AS total FROM user
|
||||||
|
```
|
||||||
|
|
||||||
|
# 案例
|
||||||
|
|
||||||
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
|
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
|
||||||
|
|
||||||
|
|
28
engine.go
28
engine.go
|
@ -320,6 +320,12 @@ func (engine *Engine) NoAutoTime() *Session {
|
||||||
return session.NoAutoTime()
|
return session.NoAutoTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) NoAutoCondition(no ...bool) *Session {
|
||||||
|
session := engine.NewSession()
|
||||||
|
session.IsAutoClose = true
|
||||||
|
return session.NoAutoCondition(no...)
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve all tables, columns, indexes' informations from database.
|
// Retrieve all tables, columns, indexes' informations from database.
|
||||||
func (engine *Engine) DBMetas() ([]*core.Table, error) {
|
func (engine *Engine) DBMetas() ([]*core.Table, error) {
|
||||||
tables, err := engine.dialect.GetTables()
|
tables, err := engine.dialect.GetTables()
|
||||||
|
@ -377,13 +383,25 @@ func (engine *Engine) DumpAll(w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, table := range tables {
|
_, err = io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s*/\n\n",
|
||||||
_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+"\n\n")
|
Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05")))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, table := range tables {
|
||||||
|
if i > 0 {
|
||||||
|
_, err = io.WriteString(w, "\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, index := range table.Indexes {
|
for _, index := range table.Indexes {
|
||||||
_, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+"\n\n")
|
_, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+";\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -443,7 +461,7 @@ func (engine *Engine) DumpAll(w io.Writer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err = io.WriteString(w, temp[2:]+");\n\n")
|
_, err = io.WriteString(w, temp[2:]+");\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -747,7 +765,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
|
||||||
if ormTagStr != "" {
|
if ormTagStr != "" {
|
||||||
col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
|
col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
|
||||||
IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]bool)}
|
IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]bool)}
|
||||||
tags := strings.Split(ormTagStr, " ")
|
tags := splitTag(ormTagStr)
|
||||||
|
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
if tags[0] == "-" {
|
if tags[0] == "-" {
|
||||||
|
|
49
helpers.go
49
helpers.go
|
@ -15,6 +15,30 @@ import (
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func splitTag(tag string) (tags []string) {
|
||||||
|
tag = strings.TrimSpace(tag)
|
||||||
|
var hasQuote = false
|
||||||
|
var lastIdx = 0
|
||||||
|
for i, t := range tag {
|
||||||
|
if t == '\'' {
|
||||||
|
hasQuote = !hasQuote
|
||||||
|
} else if t == ' ' {
|
||||||
|
if lastIdx < i && !hasQuote {
|
||||||
|
tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
|
||||||
|
lastIdx = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lastIdx < len(tag) {
|
||||||
|
tags = append(tags, strings.TrimSpace(tag[lastIdx:len(tag)]))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type zeroable interface {
|
||||||
|
IsZero() bool
|
||||||
|
}
|
||||||
|
|
||||||
func isZero(k interface{}) bool {
|
func isZero(k interface{}) bool {
|
||||||
switch k.(type) {
|
switch k.(type) {
|
||||||
case int:
|
case int:
|
||||||
|
@ -45,12 +69,33 @@ func isZero(k interface{}) bool {
|
||||||
return k.(bool) == false
|
return k.(bool) == false
|
||||||
case string:
|
case string:
|
||||||
return k.(string) == ""
|
return k.(string) == ""
|
||||||
case time.Time:
|
case zeroable:
|
||||||
return k.(time.Time).IsZero()
|
return k.(zeroable).IsZero()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func int64ToInt(id int64, k reflect.Kind) interface{} {
|
||||||
|
var v interface{} = id
|
||||||
|
switch k {
|
||||||
|
case reflect.Int16:
|
||||||
|
v = int16(id)
|
||||||
|
case reflect.Int32:
|
||||||
|
v = int32(id)
|
||||||
|
case reflect.Int:
|
||||||
|
v = int(id)
|
||||||
|
case reflect.Uint16:
|
||||||
|
v = uint16(id)
|
||||||
|
case reflect.Uint32:
|
||||||
|
v = uint32(id)
|
||||||
|
case reflect.Uint64:
|
||||||
|
v = uint64(id)
|
||||||
|
case reflect.Uint:
|
||||||
|
v = uint(id)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func isPKZero(pk core.PK) bool {
|
func isPKZero(pk core.PK) bool {
|
||||||
for _, k := range pk {
|
for _, k := range pk {
|
||||||
if isZero(k) {
|
if isZero(k) {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package xorm
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSplitTag(t *testing.T) {
|
||||||
|
var cases = []struct {
|
||||||
|
tag string
|
||||||
|
tags []string
|
||||||
|
}{
|
||||||
|
{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
|
||||||
|
{"TEXT", []string{"TEXT"}},
|
||||||
|
{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
|
||||||
|
{"json binary", []string{"json", "binary"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, kase := range cases {
|
||||||
|
tags := splitTag(kase.tag)
|
||||||
|
if !sliceEq(tags, kase.tags) {
|
||||||
|
t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ func parseURL(connstr string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.Scheme != "postgres" {
|
if u.Scheme != "postgresql" && u.Scheme != "postgres" {
|
||||||
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
|
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||||
db := &core.Uri{DbType: core.POSTGRES}
|
db := &core.Uri{DbType: core.POSTGRES}
|
||||||
o := make(values)
|
o := make(values)
|
||||||
var err error
|
var err error
|
||||||
if strings.HasPrefix(dataSourceName, "postgres://") {
|
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
|
||||||
dataSourceName, err = parseURL(dataSourceName)
|
dataSourceName, err = parseURL(dataSourceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
610
session.go
610
session.go
File diff suppressed because it is too large
Load Diff
132
statement.go
132
statement.go
|
@ -39,45 +39,46 @@ type exprParam struct {
|
||||||
|
|
||||||
// statement save all the sql info for executing SQL
|
// statement save all the sql info for executing SQL
|
||||||
type Statement struct {
|
type Statement struct {
|
||||||
RefTable *core.Table
|
RefTable *core.Table
|
||||||
Engine *Engine
|
Engine *Engine
|
||||||
Start int
|
Start int
|
||||||
LimitN int
|
LimitN int
|
||||||
WhereStr string
|
WhereStr string
|
||||||
IdParam *core.PK
|
IdParam *core.PK
|
||||||
Params []interface{}
|
Params []interface{}
|
||||||
OrderStr string
|
OrderStr string
|
||||||
JoinStr string
|
JoinStr string
|
||||||
GroupByStr string
|
GroupByStr string
|
||||||
HavingStr string
|
HavingStr string
|
||||||
ColumnStr string
|
ColumnStr string
|
||||||
selectStr string
|
selectStr string
|
||||||
columnMap map[string]bool
|
columnMap map[string]bool
|
||||||
useAllCols bool
|
useAllCols bool
|
||||||
OmitStr string
|
OmitStr string
|
||||||
ConditionStr string
|
ConditionStr string
|
||||||
AltTableName string
|
AltTableName string
|
||||||
RawSQL string
|
RawSQL string
|
||||||
RawParams []interface{}
|
RawParams []interface{}
|
||||||
UseCascade bool
|
UseCascade bool
|
||||||
UseAutoJoin bool
|
UseAutoJoin bool
|
||||||
StoreEngine string
|
StoreEngine string
|
||||||
Charset string
|
Charset string
|
||||||
BeanArgs []interface{}
|
BeanArgs []interface{}
|
||||||
UseCache bool
|
UseCache bool
|
||||||
UseAutoTime bool
|
UseAutoTime bool
|
||||||
IsDistinct bool
|
noAutoCondition bool
|
||||||
IsForUpdate bool
|
IsDistinct bool
|
||||||
TableAlias string
|
IsForUpdate bool
|
||||||
allUseBool bool
|
TableAlias string
|
||||||
checkVersion bool
|
allUseBool bool
|
||||||
unscoped bool
|
checkVersion bool
|
||||||
mustColumnMap map[string]bool
|
unscoped bool
|
||||||
nullableMap map[string]bool
|
mustColumnMap map[string]bool
|
||||||
inColumns map[string]*inParam
|
nullableMap map[string]bool
|
||||||
incrColumns map[string]incrParam
|
inColumns map[string]*inParam
|
||||||
decrColumns map[string]decrParam
|
incrColumns map[string]incrParam
|
||||||
exprColumns map[string]exprParam
|
decrColumns map[string]decrParam
|
||||||
|
exprColumns map[string]exprParam
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
|
@ -103,6 +104,7 @@ func (statement *Statement) Init() {
|
||||||
statement.BeanArgs = make([]interface{}, 0)
|
statement.BeanArgs = make([]interface{}, 0)
|
||||||
statement.UseCache = true
|
statement.UseCache = true
|
||||||
statement.UseAutoTime = true
|
statement.UseAutoTime = true
|
||||||
|
statement.noAutoCondition = false
|
||||||
statement.IsDistinct = false
|
statement.IsDistinct = false
|
||||||
statement.IsForUpdate = false
|
statement.IsForUpdate = false
|
||||||
statement.TableAlias = ""
|
statement.TableAlias = ""
|
||||||
|
@ -119,6 +121,15 @@ func (statement *Statement) Init() {
|
||||||
statement.exprColumns = make(map[string]exprParam)
|
statement.exprColumns = make(map[string]exprParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoAutoCondition
|
||||||
|
func (statement *Statement) NoAutoCondition(no ...bool) *Statement {
|
||||||
|
statement.noAutoCondition = true
|
||||||
|
if len(no) > 0 {
|
||||||
|
statement.noAutoCondition = no[0]
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
|
||||||
// add the raw sql statement
|
// add the raw sql statement
|
||||||
func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
|
func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
|
||||||
statement.RawSQL = querystring
|
statement.RawSQL = querystring
|
||||||
|
@ -182,7 +193,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto generating conditions according a struct
|
// Auto generating update columnes and values according a struct
|
||||||
func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||||
includeVersion bool, includeUpdated bool, includeNil bool,
|
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||||
includeAutoIncr bool, allUseBool bool, useAllCols bool,
|
includeAutoIncr bool, allUseBool bool, useAllCols bool,
|
||||||
|
@ -211,10 +222,6 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValuePtr, err := col.ValueOf(bean)
|
fieldValuePtr, err := col.ValueOf(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
engine.LogError(err)
|
engine.LogError(err)
|
||||||
|
@ -338,7 +345,6 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||||
if len(table.PrimaryKeys) == 1 {
|
if len(table.PrimaryKeys) == 1 {
|
||||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||||
// fix non-int pk issues
|
// fix non-int pk issues
|
||||||
//if pkField.Int() != 0 {
|
|
||||||
if pkField.IsValid() && !isZero(pkField.Interface()) {
|
if pkField.IsValid() && !isZero(pkField.Interface()) {
|
||||||
val = pkField.Interface()
|
val = pkField.Interface()
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,11 +370,13 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Array, reflect.Slice, reflect.Map:
|
case reflect.Array, reflect.Slice, reflect.Map:
|
||||||
if fieldValue == reflect.Zero(fieldType) {
|
if !requiredField {
|
||||||
continue
|
if fieldValue == reflect.Zero(fieldType) {
|
||||||
}
|
continue
|
||||||
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
}
|
||||||
continue
|
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
|
@ -1122,12 +1130,14 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
|
||||||
|
|
||||||
var addedTableName = (len(statement.JoinStr) > 0)
|
var addedTableName = (len(statement.JoinStr) > 0)
|
||||||
|
|
||||||
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
|
if !statement.noAutoCondition {
|
||||||
false, true, statement.allUseBool, statement.useAllCols,
|
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
|
||||||
statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
|
false, true, statement.allUseBool, statement.useAllCols,
|
||||||
|
statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
|
||||||
|
|
||||||
statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
|
statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
|
||||||
statement.BeanArgs = args
|
statement.BeanArgs = args
|
||||||
|
}
|
||||||
|
|
||||||
var columnStr string = statement.ColumnStr
|
var columnStr string = statement.ColumnStr
|
||||||
if len(statement.selectStr) > 0 {
|
if len(statement.selectStr) > 0 {
|
||||||
|
@ -1183,12 +1193,14 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}
|
||||||
|
|
||||||
var addedTableName = (len(statement.JoinStr) > 0)
|
var addedTableName = (len(statement.JoinStr) > 0)
|
||||||
|
|
||||||
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
|
if !statement.noAutoCondition {
|
||||||
true, statement.allUseBool, statement.useAllCols,
|
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
|
||||||
statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
|
true, statement.allUseBool, statement.useAllCols,
|
||||||
|
statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
|
||||||
|
|
||||||
statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
|
statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
|
||||||
statement.BeanArgs = args
|
statement.BeanArgs = args
|
||||||
|
}
|
||||||
|
|
||||||
// count(index fieldname) > count(0) > count(*)
|
// count(index fieldname) > count(0) > count(*)
|
||||||
var id string = "*"
|
var id string = "*"
|
||||||
|
|
Loading…
Reference in New Issue