update latest xorm version to vendor (#2353)

release/v1.2
Lunny Xiao 6 years ago committed by Lauris BH
parent 5c29b0a5fe
commit 2c6a0fdca8

@ -31,7 +31,7 @@ import (
// Engine represents a xorm engine or session.
type Engine interface {
Table(tableNameOrBean interface{}) *xorm.Session
Count(interface{}) (int64, error)
Count(...interface{}) (int64, error)
Decr(column string, arg ...interface{}) *xorm.Session
Delete(interface{}) (int64, error)
Exec(string, ...interface{}) (sql.Result, error)

@ -13,12 +13,13 @@ const (
ONLYFROMDB
)
// database column
// Column defines database column
type Column struct {
Name string
TableName string
FieldName string
SQLType SQLType
IsJSON bool
Length int
Length2 int
Nullable bool
@ -37,6 +38,7 @@ type Column struct {
SetOptions map[string]int
DisableTimeZone bool
TimeZone *time.Location // column specified time zone
Comment string
}
func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
@ -60,6 +62,7 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable
IsVersion: false,
DefaultIsEmpty: false,
EnumOptions: make(map[string]int),
Comment: "",
}
}

@ -244,6 +244,9 @@ func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset stri
sql += col.StringNoPk(b.dialect)
}
sql = strings.TrimSpace(sql)
if b.DriverName() == MYSQL && len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ", "
}

@ -247,6 +247,18 @@ type Row struct {
err error // deferred error for easy chaining
}
// ErrorRow return an error row
func ErrorRow(err error) *Row {
return &Row{
err: err,
}
}
// NewRow from rows
func NewRow(rows *Rows, err error) *Row {
return &Row{rows, err}
}
func (row *Row) Columns() ([]string, error) {
if row.err != nil {
return nil, row.err

@ -22,6 +22,7 @@ type Table struct {
Cacher Cacher
StoreEngine string
Charset string
Comment string
}
func (table *Table) Columns() []*Column {

@ -2,11 +2,9 @@
Xorm is a simple and powerful ORM for Go.
[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
# Notice
The last master version is not backwards compatible. You should use `engine.ShowSQL()` and `engine.Logger().SetLevel()` instead of `engine.ShowSQL = `, `engine.ShowInfo = ` and so on.
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
# Features
@ -50,6 +48,14 @@ Drivers for Go's sql package which currently support database/sql includes:
# Changelog
* **v0.6.3**
* merge tests to main project
* add `Exist` function
* add `SumInt` function
* Mysql now support read and create column comment.
* fix time related bugs.
* fix some other bugs.
* **v0.6.2**
* refactor tag parse methods
* add Scan features to Get
@ -62,22 +68,6 @@ methods can use `builder.Cond` as parameter
* add Sum, SumInt, SumInt64 and NotIn methods
* some bugs fixed
* **v0.5.0**
* logging interface changed
* some bugs fixed
* **v0.4.5**
* many bugs fixed
* extends support unlimited deepth
* Delete Limit support
* **v0.4.4**
* ql database expriment support
* tidb database expriment support
* sql.NullString and etc. field support
* select ForUpdate support
* many bugs fixed
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
# Installation
@ -124,7 +114,7 @@ results, err := engine.Query("select * from user")
results, err := engine.QueryString("select * from user")
```
* `Execute` runs a SQL string, it returns `affetcted` and `error`
* `Execute` runs a SQL string, it returns `affected` and `error`
```Go
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
@ -166,6 +156,25 @@ has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
```
* Check if one record exist on table
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* Query multiple records from database, also you can use join and extends
```Go
@ -258,13 +267,21 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
# Cases
* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel)

@ -4,11 +4,9 @@
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
# 注意
最新的版本有不兼容的更新,您必须使用 `engine.ShowSQL()``engine.Logger().SetLevel()` 来替代 `engine.ShowSQL = `, `engine.ShowInfo = ` 等等。
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
## 特性
@ -54,9 +52,18 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
## 更新日志
* **v0.6.3**
* 合并单元测试到主工程
* 新增`Exist`方法
* 新增`SumInt`方法
* Mysql新增读取和创建字段注释支持
* 新增`SetConnMaxLifetime`方法
* 修正了时间相关的Bug
* 修复了一些其它Bug
* **v0.6.2**
* 重构Tag解析方式
* Get方法新增类似Sacn的特性
* Get方法新增类似Scan的特性
* 新增 QueryString 方法
* **v0.6.0**
@ -70,18 +77,6 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
* logging接口进行不兼容改变
* Bug修正
* **v0.4.5**
* bug修正
* extends 支持无限级
* Delete Limit 支持
* **v0.4.4**
* Tidb 数据库支持
* QL 试验性支持
* sql.NullString支持
* ForUpdate 支持
* bug修正
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
## 安装
@ -170,6 +165,25 @@ has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
```
* 检测记录是否存在
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* 查询多条记录当然可以使用Join和extends来组合使用
```Go
@ -261,13 +275,21 @@ err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))
# 案例
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)

@ -3,6 +3,8 @@ dependencies:
# './...' is a relative pattern which means all subdirectories
- go get -t -d -v ./...
- go get -t -d -v github.com/go-xorm/tests
- go get -u github.com/go-xorm/core
- go get -u github.com/go-xorm/builder
- go build -v
database:
@ -19,7 +21,9 @@ database:
test:
override:
# './...' is a relative pattern which means all subdirectories
- go test -v -race
- go test -v -race -db="sqlite3::mysql::mymysql::postgres" -conn_str="./test.db::root:@/xorm_test::xorm_test/root/::dbname=xorm_test sslmode=disable" -coverprofile=coverage.txt -covermode=atomic
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
post:
- bash <(curl -s https://codecov.io/bash)

@ -215,7 +215,7 @@ func (db *mssql) SqlType(c *core.Column) string {
var res string
switch t := c.SQLType.Name; t {
case core.Bool:
res = core.TinyInt
res = core.Bit
if strings.EqualFold(c.Default, "true") {
c.Default = "1"
} else {
@ -250,6 +250,9 @@ func (db *mssql) SqlType(c *core.Column) string {
case core.Uuid:
res = core.Varchar
c.Length = 40
case core.TinyInt:
res = core.TinyInt
c.Length = 0
default:
res = t
}
@ -335,9 +338,15 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
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,a.is_nullable as nullable,
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault
from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
left join sys.syscomments c on a.default_object_id=c.id
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
ISNULL(i.is_primary_key, 0)
from sys.columns a
left join sys.types b on a.user_type_id=b.user_type_id
left join sys.syscomments c on a.default_object_id=c.id
LEFT OUTER JOIN
sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
LEFT OUTER JOIN
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
where a.object_id=object_id('` + tableName + `')`
db.LogSQL(s, args)
@ -352,8 +361,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
for rows.Next() {
var name, ctype, vdefault string
var maxLen, precision, scale int
var nullable bool
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault)
var nullable, isPK bool
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
if err != nil {
return nil, nil, err
}
@ -363,6 +372,7 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
col.Name = strings.Trim(name, "` ")
col.Nullable = nullable
col.Default = vdefault
col.IsPrimaryKey = isPK
ct := strings.ToUpper(ctype)
if ct == "DECIMAL" {
col.Length = precision
@ -536,7 +546,6 @@ type odbcDriver struct {
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
kv := strings.Split(dataSourceName, ";")
var dbName string
for _, c := range kv {
vv := strings.Split(strings.TrimSpace(c), "=")
if len(vv) == 2 {

@ -299,7 +299,7 @@ func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
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` = ?"
" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
@ -314,13 +314,14 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
col := new(core.Column)
col.Indexes = make(map[string]int)
var columnName, isNullable, colType, colKey, extra string
var columnName, isNullable, colType, colKey, extra, comment string
var colDefault *string
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra)
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
if err != nil {
return nil, nil, err
}
col.Name = strings.Trim(columnName, "` ")
col.Comment = comment
if "YES" == isNullable {
col.Nullable = true
}
@ -407,7 +408,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
func (db *mysql) GetTables() ([]*core.Table, error) {
args := []interface{}{db.DbName}
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
db.LogSQL(s, args)
@ -420,14 +421,15 @@ func (db *mysql) GetTables() ([]*core.Table, error) {
tables := make([]*core.Table, 0)
for rows.Next() {
table := core.NewEmptyTable()
var name, engine, tableRows string
var name, engine, tableRows, comment string
var autoIncr *string
err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
if err != nil {
return nil, err
}
table.Name = name
table.Comment = comment
table.StoreEngine = engine
tables = append(tables, table)
}

@ -14,10 +14,6 @@ import (
"github.com/go-xorm/core"
)
// func init() {
// RegisterDialect("sqlite3", &sqlite3{})
// }
var (
sqlite3ReservedWords = map[string]bool{
"ABORT": true,
@ -310,11 +306,25 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
for _, colStr := range colCreates {
reg = regexp.MustCompile(`,\s`)
colStr = reg.ReplaceAllString(colStr, ",")
if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") {
parts := strings.Split(strings.TrimSpace(colStr), "(")
if len(parts) == 2 {
pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",")
for _, pk := range pkCols {
if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok {
col.IsPrimaryKey = true
}
}
}
continue
}
fields := strings.Fields(strings.TrimSpace(colStr))
col := new(core.Column)
col.Indexes = make(map[string]int)
col.Nullable = true
col.DefaultIsEmpty = true
for idx, field := range fields {
if idx == 0 {
col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)

@ -8,7 +8,7 @@ Package xorm is a simple and powerful ORM for Go.
Installation
Make sure you have installed Go 1.1+ and then:
Make sure you have installed Go 1.6+ and then:
go get github.com/go-xorm/xorm
@ -51,11 +51,15 @@ There are 8 major ORM methods and many helpful methods to use to operate databas
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
2. Query one record from database
2. Query one record or one variable from database
has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1
var id int64
has, err := engine.Table("user").Where("name = ?", name).Get(&id)
// SELECT id FROM user WHERE name = ? LIMIT 1
3. Query multiple records from database
var sliceOfStructs []Struct
@ -99,6 +103,9 @@ another is Rows
counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user
counts, err := engine.SQL("select count(*) FROM user").Count()
// select count(*) FROM user
8. Sum records
sumFloat64, err := engine.Sum(&user, "id")

@ -19,6 +19,7 @@ import (
"sync"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
@ -40,7 +41,7 @@ type Engine struct {
showExecTime bool
logger core.ILogger
TZLocation *time.Location
TZLocation *time.Location // The timezone of the application
DatabaseTZ *time.Location // The timezone of the database
disableGlobalCache bool
@ -143,7 +144,6 @@ func (engine *Engine) Quote(value string) string {
// QuoteTo quotes string and writes into the buffer
func (engine *Engine) QuoteTo(buf *bytes.Buffer, value string) {
if buf == nil {
return
}
@ -169,7 +169,7 @@ func (engine *Engine) quote(sql string) string {
return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
}
// SqlType will be depracated, please use SQLType instead
// SqlType will be deprecated, please use SQLType instead
//
// Deprecated: use SQLType instead
func (engine *Engine) SqlType(c *core.Column) string {
@ -205,14 +205,14 @@ func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
// you can use NoCache()
func (engine *Engine) NoCache() *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.NoCache()
}
// NoCascade If you do not want to auto cascade load object
func (engine *Engine) NoCascade() *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.NoCascade()
}
@ -245,7 +245,7 @@ func (engine *Engine) Dialect() core.Dialect {
// NewSession New a session
func (engine *Engine) NewSession() *Session {
session := &Session{Engine: engine}
session := &Session{engine: engine}
session.Init()
return session
}
@ -259,7 +259,6 @@ func (engine *Engine) Close() error {
func (engine *Engine) Ping() error {
session := engine.NewSession()
defer session.Close()
engine.logger.Infof("PING DATABASE %v", engine.DriverName())
return session.Ping()
}
@ -267,7 +266,7 @@ func (engine *Engine) Ping() error {
func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
if engine.showSQL && !engine.showExecTime {
if len(sqlArgs) > 0 {
engine.logger.Infof("[SQL] %v %v", sqlStr, sqlArgs)
engine.logger.Infof("[SQL] %v %#v", sqlStr, sqlArgs)
} else {
engine.logger.Infof("[SQL] %v", sqlStr)
}
@ -320,7 +319,7 @@ func (engine *Engine) Sql(querystring string, args ...interface{}) *Session {
// This code will execute "select * from user" and set the records to users
func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.SQL(query, args...)
}
@ -329,14 +328,14 @@ func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
// invoked. Call NoAutoTime if you dont' want to fill automatically.
func (engine *Engine) NoAutoTime() *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.NoAutoTime()
}
// NoAutoCondition disable auto generate Where condition from bean or not
func (engine *Engine) NoAutoCondition(no ...bool) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.NoAutoCondition(no...)
}
@ -570,56 +569,56 @@ func (engine *Engine) tbName(v reflect.Value) string {
// Cascade use cascade or not
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Cascade(trueOrFalse...)
}
// Where method provide a condition query
func (engine *Engine) Where(query interface{}, args ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Where(query, args...)
}
// Id will be depracated, please use ID instead
// Id will be deprecated, please use ID instead
func (engine *Engine) Id(id interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Id(id)
}
// ID method provoide a condition as (id) = ?
func (engine *Engine) ID(id interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.ID(id)
}
// Before apply before Processor, affected bean is passed to closure arg
func (engine *Engine) Before(closures func(interface{})) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Before(closures)
}
// After apply after insert Processor, affected bean is passed to closure arg
func (engine *Engine) After(closures func(interface{})) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.After(closures)
}
// Charset set charset when create table, only support mysql now
func (engine *Engine) Charset(charset string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Charset(charset)
}
// StoreEngine set store engine when create table, only support mysql now
func (engine *Engine) StoreEngine(storeEngine string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.StoreEngine(storeEngine)
}
@ -628,35 +627,35 @@ func (engine *Engine) StoreEngine(storeEngine string) *Session {
// but distinct will not provide id
func (engine *Engine) Distinct(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Distinct(columns...)
}
// Select customerize your select columns or contents
func (engine *Engine) Select(str string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Select(str)
}
// Cols only use the parameters as select or update columns
func (engine *Engine) Cols(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Cols(columns...)
}
// AllCols indicates that all columns should be use
func (engine *Engine) AllCols() *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.AllCols()
}
// MustCols specify some columns must use even if they are empty
func (engine *Engine) MustCols(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.MustCols(columns...)
}
@ -667,77 +666,84 @@ func (engine *Engine) MustCols(columns ...string) *Session {
// it will use parameters's columns
func (engine *Engine) UseBool(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.UseBool(columns...)
}
// Omit only not use the parameters as select or update columns
func (engine *Engine) Omit(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Omit(columns...)
}
// Nullable set null when column is zero-value and nullable for update
func (engine *Engine) Nullable(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Nullable(columns...)
}
// In will generate "column IN (?, ?)"
func (engine *Engine) In(column string, args ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.In(column, args...)
}
// NotIn will generate "column NOT IN (?, ?)"
func (engine *Engine) NotIn(column string, args ...interface{}) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.NotIn(column, args...)
}
// Incr provides a update string like "column = column + ?"
func (engine *Engine) Incr(column string, arg ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Incr(column, arg...)
}
// Decr provides a update string like "column = column - ?"
func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Decr(column, arg...)
}
// SetExpr provides a update string like "column = {expression}"
func (engine *Engine) SetExpr(column string, expression string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.SetExpr(column, expression)
}
// Table temporarily change the Get, Find, Update's table
func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Table(tableNameOrBean)
}
// Alias set the table alias
func (engine *Engine) Alias(alias string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Alias(alias)
}
// Limit will generate "LIMIT start, limit"
func (engine *Engine) Limit(limit int, start ...int) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Limit(limit, start...)
}
// Desc will generate "ORDER BY column1 DESC, column2 DESC"
func (engine *Engine) Desc(colNames ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Desc(colNames...)
}
@ -749,38 +755,44 @@ func (engine *Engine) Desc(colNames ...string) *Session {
//
func (engine *Engine) Asc(colNames ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Asc(colNames...)
}
// OrderBy will generate "ORDER BY order"
func (engine *Engine) OrderBy(order string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.OrderBy(order)
}
// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Join(joinOperator, tablename, condition, args...)
}
// GroupBy generate group by statement
func (engine *Engine) GroupBy(keys string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.GroupBy(keys)
}
// Having generate having statement
func (engine *Engine) Having(conditions string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Having(conditions)
}
func (engine *Engine) unMapType(t reflect.Type) {
engine.mutex.Lock()
defer engine.mutex.Unlock()
delete(engine.Tables, t)
}
func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) {
t := v.Type()
engine.mutex.Lock()
@ -1007,6 +1019,10 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name),
t.Field(i).Name, sqlType, sqlType.DefaultLength,
sqlType.DefaultLength2, true)
if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
idFieldColName = col.Name
}
}
if col.IsAutoIncrement {
col.Nullable = false
@ -1014,9 +1030,6 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
table.AddColumn(col)
if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
idFieldColName = col.Name
}
} // end for
if idFieldColName != "" && len(table.PrimaryKeys) == 0 {
@ -1097,19 +1110,39 @@ func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) {
pk := make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
var err error
pkField := v.FieldByName(col.FieldName)
switch pkField.Kind() {
case reflect.String:
pk[i] = pkField.String()
pk[i], err = engine.idTypeAssertion(col, pkField.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
pk[i] = pkField.Int()
pk[i], err = engine.idTypeAssertion(col, strconv.FormatInt(pkField.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
pk[i] = pkField.Uint()
// id of uint will be converted to int64
pk[i], err = engine.idTypeAssertion(col, strconv.FormatUint(pkField.Uint(), 10))
}
if err != nil {
return nil, err
}
}
return core.PK(pk), nil
}
func (engine *Engine) idTypeAssertion(col *core.Column, sid string) (interface{}, error) {
if col.SQLType.IsNumeric() {
n, err := strconv.ParseInt(sid, 10, 64)
if err != nil {
return nil, err
}
return n, nil
} else if col.SQLType.IsText() {
return sid, nil
} else {
return nil, errors.New("not supported")
}
}
// CreateIndexes create indexes
func (engine *Engine) CreateIndexes(bean interface{}) error {
session := engine.NewSession()
@ -1181,6 +1214,9 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
// table, column, index, unique. but will not delete or change anything.
// If you change some field, you should change the database manually.
func (engine *Engine) Sync(beans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
for _, bean := range beans {
v := rValue(bean)
tableName := engine.tbName(v)
@ -1189,14 +1225,12 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err
}
s := engine.NewSession()
defer s.Close()
isExist, err := s.Table(bean).isTableExist(tableName)
isExist, err := session.Table(bean).isTableExist(tableName)
if err != nil {
return err
}
if !isExist {
err = engine.CreateTables(bean)
err = session.createTable(bean)
if err != nil {
return err
}
@ -1207,11 +1241,11 @@ func (engine *Engine) Sync(beans ...interface{}) error {
}*/
var isEmpty bool
if isEmpty {
err = engine.DropTables(bean)
err = session.dropTable(bean)
if err != nil {
return err
}
err = engine.CreateTables(bean)
err = session.createTable(bean)
if err != nil {
return err
}
@ -1222,9 +1256,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err
}
if !isExist {
session := engine.NewSession()
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
if err := session.statement.setRefValue(v); err != nil {
return err
}
err = session.addColumn(col.Name)
@ -1235,21 +1267,16 @@ func (engine *Engine) Sync(beans ...interface{}) error {
}
for name, index := range table.Indexes {
session := engine.NewSession()
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
if err := session.statement.setRefValue(v); err != nil {
return err
}
if index.Type == core.UniqueType {
//isExist, err := session.isIndexExist(table.Name, name, true)
isExist, err := session.isIndexExist2(tableName, index.Cols, true)
if err != nil {
return err
}
if !isExist {
session := engine.NewSession()
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
if err := session.statement.setRefValue(v); err != nil {
return err
}
@ -1264,9 +1291,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return err
}
if !isExist {
session := engine.NewSession()
defer session.Close()
if err := session.Statement.setRefValue(v); err != nil {
if err := session.statement.setRefValue(v); err != nil {
return err
}
@ -1291,23 +1316,6 @@ func (engine *Engine) Sync2(beans ...interface{}) error {
return s.Sync2(beans...)
}
// Drop all mapped table
func (engine *Engine) dropAll() error {
session := engine.NewSession()
defer session.Close()
err := session.Begin()
if err != nil {
return err
}
err = session.dropAll()
if err != nil {
session.Rollback()
return err
}
return session.Commit()
}
// CreateTables create tabls according bean
func (engine *Engine) CreateTables(beans ...interface{}) error {
session := engine.NewSession()
@ -1319,7 +1327,7 @@ func (engine *Engine) CreateTables(beans ...interface{}) error {
}
for _, bean := range beans {
err = session.CreateTable(bean)
err = session.createTable(bean)
if err != nil {
session.Rollback()
return err
@ -1339,7 +1347,7 @@ func (engine *Engine) DropTables(beans ...interface{}) error {
}
for _, bean := range beans {
err = session.DropTable(bean)
err = session.dropTable(bean)
if err != nil {
session.Rollback()
return err
@ -1348,10 +1356,11 @@ func (engine *Engine) DropTables(beans ...interface{}) error {
return session.Commit()
}
func (engine *Engine) createAll() error {
// DropIndexes drop indexes of a table
func (engine *Engine) DropIndexes(bean interface{}) error {
session := engine.NewSession()
defer session.Close()
return session.createAll()
return session.DropIndexes(bean)
}
// Exec raw sql
@ -1416,6 +1425,13 @@ func (engine *Engine) Get(bean interface{}) (bool, error) {
return session.Get(bean)
}
// Exist returns true if the record exist otherwise return false
func (engine *Engine) Exist(bean ...interface{}) (bool, error) {
session := engine.NewSession()
defer session.Close()
return session.Exist(bean...)
}
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
@ -1441,10 +1457,10 @@ func (engine *Engine) Rows(bean interface{}) (*Rows, error) {
}
// Count counts the records. bean's non-empty fields are conditions.
func (engine *Engine) Count(bean interface{}) (int64, error) {
func (engine *Engine) Count(bean ...interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.Count(bean)
return session.Count(bean...)
}
// Sum sum the records by some column. bean's non-empty fields are conditions.
@ -1454,6 +1470,13 @@ func (engine *Engine) Sum(bean interface{}, colName string) (float64, error) {
return session.Sum(bean, colName)
}
// SumInt sum the records by some column. bean's non-empty fields are conditions.
func (engine *Engine) SumInt(bean interface{}, colName string) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.SumInt(bean, colName)
}
// Sums sum the records by some columns. bean's non-empty fields are conditions.
func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) {
session := engine.NewSession()
@ -1509,7 +1532,6 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
results = append(results, result)
if err != nil {
return nil, err
//lastError = err
}
}
}
@ -1517,49 +1539,28 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
return results, lastError
}
// TZTime change one time to xorm time location
func (engine *Engine) TZTime(t time.Time) time.Time {
if !t.IsZero() { // if time is not initialized it's not suitable for Time.In()
return t.In(engine.TZLocation)
}
return t
}
// NowTime return current time
func (engine *Engine) NowTime(sqlTypeName string) interface{} {
t := time.Now()
return engine.FormatTime(sqlTypeName, t)
}
// NowTime2 return current time
func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) {
t := time.Now()
return engine.FormatTime(sqlTypeName, t), t
}
// FormatTime format time
func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) {
return engine.formatTime(engine.TZLocation, sqlTypeName, t)
return engine.formatTime(sqlTypeName, t.In(engine.DatabaseTZ)), t.In(engine.TZLocation)
}
func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
if col.DisableTimeZone {
return engine.formatTime(nil, col.SQLType.Name, t)
} else if col.TimeZone != nil {
return engine.formatTime(col.TimeZone, col.SQLType.Name, t)
if t.IsZero() {
if col.Nullable {
return nil
}
return ""
}
return engine.formatTime(engine.TZLocation, col.SQLType.Name, t)
}
func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.Time) (v interface{}) {
if engine.dialect.DBType() == core.ORACLE {
return t
}
if tz != nil {
t = t.In(tz)
} else {
t = engine.TZTime(t)
if col.TimeZone != nil {
return engine.formatTime(col.SQLType.Name, t.In(col.TimeZone))
}
return engine.formatTime(col.SQLType.Name, t.In(engine.DatabaseTZ))
}
// formatTime format time as column type
func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) {
switch sqlTypeName {
case core.Time:
s := t.Format("2006-01-02 15:04:05") //time.RFC3339
@ -1567,18 +1568,10 @@ func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.T
case core.Date:
v = t.Format("2006-01-02")
case core.DateTime, core.TimeStamp:
if engine.dialect.DBType() == "ql" {
v = t
} else if engine.dialect.DBType() == "sqlite3" {
v = t.UTC().Format("2006-01-02 15:04:05")
} else {
v = t.Format("2006-01-02 15:04:05")
}
v = t.Format("2006-01-02 15:04:05")
case core.TimeStampz:
if engine.dialect.DBType() == core.MSSQL {
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
} else if engine.DriverName() == "mssql" {
v = t
} else {
v = t.Format(time.RFC3339Nano)
}
@ -1593,6 +1586,14 @@ func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.T
// Unscoped always disable struct tag "deleted"
func (engine *Engine) Unscoped() *Session {
session := engine.NewSession()
session.IsAutoClose = true
session.isAutoClose = true
return session.Unscoped()
}
// CondDeleted returns the conditions whether a record is soft deleted.
func (engine *Engine) CondDeleted(colName string) builder.Cond {
if engine.dialect.DBType() == core.MSSQL {
return builder.IsNull{colName}
}
return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1})
}

@ -0,0 +1,230 @@
// Copyright 2017 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (engine *Engine) buildConds(table *core.Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool,
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
var conds []builder.Cond
for _, col := range table.Columns() {
if !includeVersion && col.IsVersion {
continue
}
if !includeUpdated && col.IsUpdated {
continue
}
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
continue
}
if col.SQLType.IsJson() {
continue
}
var colName string
if addedTableName {
var nm = tableName
if len(aliasName) > 0 {
nm = aliasName
}