commit
7826f88534
|
|
@ -1,2 +1,2 @@
|
||||||
[target]
|
[target]
|
||||||
path = github.com/lunny/xorm
|
path = github.com/go-xorm/xorm
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
## Contributing to xorm
|
## Contributing to xorm
|
||||||
|
|
||||||
`xorm` has a backlog of pull requests, but contributions are still very
|
`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very
|
||||||
much welcome. You can help with patch review, submitting bug reports,
|
much welcome. You can help with patch review, submitting bug reports,
|
||||||
or adding new functionality. There is no formal style guide, but
|
or adding new functionality. There is no formal style guide, but
|
||||||
please conform to the style of existing code and general Go formatting
|
please conform to the style of existing code and general Go formatting
|
||||||
conventions when submitting patches.
|
conventions when submitting patches.
|
||||||
|
|
||||||
|
* [fork a repo](https://help.github.com/articles/fork-a-repo)
|
||||||
|
* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
|
||||||
|
|
||||||
### Patch review
|
### Patch review
|
||||||
|
|
||||||
Help review existing open pull requests by commenting on the code or
|
Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or
|
||||||
proposed functionality.
|
proposed functionality.
|
||||||
|
|
||||||
### Bug reports
|
### Bug reports
|
||||||
|
|
@ -18,11 +21,11 @@ We appreciate any bug reports, but especially ones with self-contained
|
||||||
further) test cases. It's especially helpful if you can submit a pull
|
further) test cases. It's especially helpful if you can submit a pull
|
||||||
request with just the failing test case (you'll probably want to
|
request with just the failing test case (you'll probably want to
|
||||||
pattern it after the tests in
|
pattern it after the tests in
|
||||||
[base_test.go](https://github.com/lunny/xorm/blob/master/base_test.go) AND
|
[base_test.go](https://github.com/go-xorm/xorm/blob/master/base_test.go) AND
|
||||||
[benchmark_base_test.go](https://github.com/lunny/xorm/blob/master/benchmark_base_test.go).
|
[benchmark_base_test.go](https://github.com/go-xorm/xorm/blob/master/benchmark_base_test.go).
|
||||||
|
|
||||||
If you implements a new database interface, you maybe need to add a <databasename>_test.go file.
|
If you implements a new database interface, you maybe need to add a <databasename>_test.go file.
|
||||||
For example, [mysql_test.go](https://github.com/lunny/xorm/blob/master/mysql_test.go)
|
For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/mysql_test.go)
|
||||||
|
|
||||||
### New functionality
|
### New functionality
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013 - 2014
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the {organization} nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
28
README.md
28
README.md
|
|
@ -1,8 +1,8 @@
|
||||||
[中文](https://github.com/lunny/xorm/blob/master/README_CN.md)
|
[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md)
|
||||||
|
|
||||||
Xorm is a simple and powerful ORM for Go.
|
Xorm is a simple and powerful ORM for Go.
|
||||||
|
|
||||||
[](https://drone.io/github.com/lunny/xorm/latest) [](http://gowalker.org/github.com/lunny/xorm) [](https://bitdeli.com/free "Bitdeli Badge")
|
[](https://drone.io/github.com/go-xorm/xorm/latest) [](http://gowalker.org/github.com/go-xorm/xorm) [](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ Xorm is a simple and powerful ORM for Go.
|
||||||
|
|
||||||
* Query Cache speed up
|
* Query Cache speed up
|
||||||
|
|
||||||
* Database Reverse support, See [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md)
|
* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md)
|
||||||
|
|
||||||
* Simple cascade loading support
|
* Simple cascade loading support
|
||||||
|
|
||||||
|
|
@ -54,39 +54,41 @@ Drivers for Go's sql package which currently support database/sql includes:
|
||||||
* Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type
|
* Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type
|
||||||
* Performance improvement for Get()/Find()/Iterate()
|
* Performance improvement for Get()/Find()/Iterate()
|
||||||
|
|
||||||
[More changelogs ...](https://github.com/lunny/xorm/blob/master/docs/Changelog.md)
|
[More changelogs ...](https://github.com/go-xorm/xorm/blob/master/docs/Changelog.md)
|
||||||
|
|
||||||
# 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/lunny/xorm
|
gopm get github.com/go-xorm/xorm
|
||||||
|
|
||||||
Or
|
Or
|
||||||
|
|
||||||
go get github.com/lunny/xorm
|
go get github.com/go-xorm/xorm
|
||||||
|
|
||||||
# Documents
|
# Documents
|
||||||
|
|
||||||
* [GoDoc](http://godoc.org/github.com/lunny/xorm)
|
* [GoDoc](http://godoc.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
* [GoWalker](http://gowalker.org/github.com/lunny/xorm)
|
* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
* [Quick Start](https://github.com/lunny/xorm/blob/master/docs/QuickStartEn.md)
|
* [Quick Start](https://github.com/go-xorm/xorm/blob/master/docs/QuickStartEn.md)
|
||||||
|
|
||||||
# Cases
|
# Cases
|
||||||
|
|
||||||
|
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
|
||||||
|
|
||||||
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
||||||
|
|
||||||
|
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
|
||||||
|
|
||||||
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
|
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
|
||||||
|
|
||||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
||||||
|
|
||||||
* [Very Hour](http://veryhour.com/)
|
* [Very Hour](http://veryhour.com/)
|
||||||
|
|
||||||
# Todo
|
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
|
||||||
|
|
||||||
[Todo List](https://trello.com/b/IHsuAnhk/xorm)
|
|
||||||
|
|
||||||
# Discuss
|
# Discuss
|
||||||
|
|
||||||
|
|
@ -94,7 +96,7 @@ Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xor
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
|
||||||
If you want to pull request, please see [CONTRIBUTING](https://github.com/lunny/xorm/blob/master/CONTRIBUTING.md)
|
If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
* [Lunny](https://github.com/lunny)
|
* [Lunny](https://github.com/lunny)
|
||||||
* [Nashtsai](https://github.com/nashtsai)
|
* [Nashtsai](https://github.com/nashtsai)
|
||||||
|
|
|
||||||
26
README_CN.md
26
README_CN.md
|
|
@ -1,10 +1,10 @@
|
||||||
# xorm
|
# xorm
|
||||||
|
|
||||||
[English](https://github.com/lunny/xorm/blob/master/README.md)
|
[English](https://github.com/go-xorm/xorm/blob/master/README.md)
|
||||||
|
|
||||||
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
||||||
|
|
||||||
[](https://drone.io/github.com/lunny/xorm/latest) [](http://gowalker.org/github.com/lunny/xorm)
|
[](https://drone.io/github.com/go-xorm/xorm/latest) [](http://gowalker.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
|
|
@ -56,40 +56,42 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
* 查询函数 Get()/Find()/Iterate() 在性能上的改进
|
* 查询函数 Get()/Find()/Iterate() 在性能上的改进
|
||||||
|
|
||||||
|
|
||||||
[更多更新日志...](https://github.com/lunny/xorm/blob/master/docs/ChangelogCN.md)
|
[更多更新日志...](https://github.com/go-xorm/xorm/blob/master/docs/ChangelogCN.md)
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
|
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
|
||||||
|
|
||||||
gopm get github.com/lunny/xorm
|
gopm get github.com/go-xorm/xorm
|
||||||
|
|
||||||
或者您也可以使用go工具进行安装:
|
或者您也可以使用go工具进行安装:
|
||||||
|
|
||||||
go get github.com/lunny/xorm
|
go get github.com/go-xorm/xorm
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
* [快速开始](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md)
|
* [快速开始](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md)
|
||||||
|
|
||||||
* [GoWalker代码文档](http://gowalker.org/github.com/lunny/xorm)
|
* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
* [Godoc代码文档](http://godoc.org/github.com/lunny/xorm)
|
* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
|
||||||
|
|
||||||
|
|
||||||
## 案例
|
## 案例
|
||||||
|
|
||||||
|
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
|
||||||
|
|
||||||
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
||||||
|
|
||||||
|
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
|
||||||
|
|
||||||
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
|
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
|
||||||
|
|
||||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
||||||
|
|
||||||
* [Very Hour](http://veryhour.com/)
|
* [Very Hour](http://veryhour.com/)
|
||||||
|
|
||||||
## Todo
|
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
|
||||||
|
|
||||||
[开发计划](https://trello.com/b/IHsuAnhk/xorm)
|
|
||||||
|
|
||||||
## 讨论
|
## 讨论
|
||||||
|
|
||||||
|
|
@ -97,7 +99,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
||||||
|
|
||||||
# 贡献者
|
# 贡献者
|
||||||
|
|
||||||
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/lunny/xorm/blob/master/CONTRIBUTING.md)
|
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
* [Lunny](https://github.com/lunny)
|
* [Lunny](https://github.com/lunny)
|
||||||
* [Nashtsai](https://github.com/nashtsai)
|
* [Nashtsai](https://github.com/nashtsai)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LRUCacher struct {
|
type LRUCacher struct {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
go test -v -bench=. -run=XXX
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// default cache expired time
|
|
||||||
CacheExpired = 60 * time.Minute
|
|
||||||
// not use now
|
|
||||||
CacheMaxMemory = 256
|
|
||||||
// evey ten minutes to clear all expired nodes
|
|
||||||
CacheGcInterval = 10 * time.Minute
|
|
||||||
// each time when gc to removed max nodes
|
|
||||||
CacheGcMaxRemoved = 20
|
|
||||||
)
|
|
||||||
|
|
||||||
// CacheStore is a interface to store cache
|
|
||||||
type CacheStore interface {
|
|
||||||
// key is primary key or composite primary key or unique key's value
|
|
||||||
// value is struct's pointer
|
|
||||||
// key format : <tablename>-p-<pk1>-<pk2>...
|
|
||||||
Put(key string, value interface{}) error
|
|
||||||
Get(key string) (interface{}, error)
|
|
||||||
Del(key string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cacher is an interface to provide cache
|
|
||||||
// id format : u-<pk1>-<pk2>...
|
|
||||||
type Cacher interface {
|
|
||||||
GetIds(tableName, sql string) interface{}
|
|
||||||
GetBean(tableName string, id string) interface{}
|
|
||||||
PutIds(tableName, sql string, ids interface{})
|
|
||||||
PutBean(tableName string, id string, obj interface{})
|
|
||||||
DelIds(tableName, sql string)
|
|
||||||
DelBean(tableName string, id string)
|
|
||||||
ClearIds(tableName string)
|
|
||||||
ClearBeans(tableName string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeIds(ids []PK) (string, error) {
|
|
||||||
b, err := json.Marshal(ids)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeIds(s string) ([]PK, error) {
|
|
||||||
pks := make([]PK, 0)
|
|
||||||
err := json.Unmarshal([]byte(s), &pks)
|
|
||||||
return pks, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) {
|
|
||||||
bytes := m.GetIds(tableName, GenSqlKey(sql, args))
|
|
||||||
if bytes == nil {
|
|
||||||
return nil, errors.New("Not Exist")
|
|
||||||
}
|
|
||||||
return decodeIds(bytes.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error {
|
|
||||||
bytes, err := encodeIds(ids)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.PutIds(tableName, GenSqlKey(sql, args), bytes)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenSqlKey(sql string, args interface{}) string {
|
|
||||||
return fmt.Sprintf("%v-%v", sql, args)
|
|
||||||
}
|
|
||||||
113
core/column.go
113
core/column.go
|
|
@ -1,113 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TWOSIDES = iota + 1
|
|
||||||
ONLYTODB
|
|
||||||
ONLYFROMDB
|
|
||||||
)
|
|
||||||
|
|
||||||
// database column
|
|
||||||
type Column struct {
|
|
||||||
Name string
|
|
||||||
FieldName string
|
|
||||||
SQLType SQLType
|
|
||||||
Length int
|
|
||||||
Length2 int
|
|
||||||
Nullable bool
|
|
||||||
Default string
|
|
||||||
Indexes map[string]bool
|
|
||||||
IsPrimaryKey bool
|
|
||||||
IsAutoIncrement bool
|
|
||||||
MapType int
|
|
||||||
IsCreated bool
|
|
||||||
IsUpdated bool
|
|
||||||
IsCascade bool
|
|
||||||
IsVersion bool
|
|
||||||
fieldPath []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
|
|
||||||
return &Column{name, fieldName, sqlType, len1, len2, nullable, "", make(map[string]bool), false, false,
|
|
||||||
TWOSIDES, false, false, false, false, nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate column description string according dialect
|
|
||||||
func (col *Column) String(d Dialect) string {
|
|
||||||
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
|
|
||||||
|
|
||||||
sql += d.SqlType(col) + " "
|
|
||||||
|
|
||||||
if col.IsPrimaryKey {
|
|
||||||
sql += "PRIMARY KEY "
|
|
||||||
if col.IsAutoIncrement {
|
|
||||||
sql += d.AutoIncrStr() + " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if col.Nullable {
|
|
||||||
sql += "NULL "
|
|
||||||
} else {
|
|
||||||
sql += "NOT NULL "
|
|
||||||
}
|
|
||||||
|
|
||||||
if col.Default != "" {
|
|
||||||
sql += "DEFAULT " + col.Default + " "
|
|
||||||
}
|
|
||||||
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
func (col *Column) StringNoPk(d Dialect) string {
|
|
||||||
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
|
|
||||||
|
|
||||||
sql += d.SqlType(col) + " "
|
|
||||||
|
|
||||||
if col.Nullable {
|
|
||||||
sql += "NULL "
|
|
||||||
} else {
|
|
||||||
sql += "NOT NULL "
|
|
||||||
}
|
|
||||||
|
|
||||||
if col.Default != "" {
|
|
||||||
sql += "DEFAULT " + col.Default + " "
|
|
||||||
}
|
|
||||||
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
// return col's filed of struct's value
|
|
||||||
func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
|
|
||||||
dataStruct := reflect.Indirect(reflect.ValueOf(bean))
|
|
||||||
return col.ValueOfV(&dataStruct)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
|
|
||||||
var fieldValue reflect.Value
|
|
||||||
var err error
|
|
||||||
if col.fieldPath == nil {
|
|
||||||
col.fieldPath = strings.Split(col.FieldName, ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(col.fieldPath) == 1 {
|
|
||||||
fieldValue = dataStruct.FieldByName(col.FieldName)
|
|
||||||
} else if len(col.fieldPath) == 2 {
|
|
||||||
parentField := dataStruct.FieldByName(col.fieldPath[0])
|
|
||||||
if parentField.IsValid() {
|
|
||||||
fieldValue = parentField.FieldByName(col.fieldPath[1])
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("field %v is not valid", col.FieldName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("Unsupported mutliderive %v", col.FieldName)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &fieldValue, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
// Conversion is an interface. A type implements Conversion will according
|
|
||||||
// the custom method to fill into database and retrieve from database.
|
|
||||||
type Conversion interface {
|
|
||||||
FromDB([]byte) error
|
|
||||||
ToDB() ([]byte, error)
|
|
||||||
}
|
|
||||||
566
core/db.go
566
core/db.go
|
|
@ -1,566 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrNoMapPointer = errors.New("mp should be a map's pointer")
|
|
||||||
ErrNoStructPointer = errors.New("mp should be a map's pointer")
|
|
||||||
)
|
|
||||||
|
|
||||||
func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
|
|
||||||
vv := reflect.ValueOf(mp)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return "", []interface{}{}, ErrNoMapPointer
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, 0)
|
|
||||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
|
||||||
args = append(args, vv.Elem().MapIndex(reflect.ValueOf(src[1:])).Interface())
|
|
||||||
return "?"
|
|
||||||
})
|
|
||||||
return query, args, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
|
|
||||||
vv := reflect.ValueOf(st)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return "", []interface{}{}, ErrNoStructPointer
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, 0)
|
|
||||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
|
||||||
args = append(args, vv.Elem().FieldByName(src[1:]).Interface())
|
|
||||||
return "?"
|
|
||||||
})
|
|
||||||
return query, args, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DB struct {
|
|
||||||
*sql.DB
|
|
||||||
Mapper IMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func Open(driverName, dataSourceName string) (*DB, error) {
|
|
||||||
db, err := sql.Open(driverName, dataSourceName)
|
|
||||||
return &DB{db, NewCacheMapper(&SnakeMapper{})}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
|
|
||||||
rows, err := db.DB.Query(query, args...)
|
|
||||||
return &Rows{rows, db.Mapper}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return db.Query(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return db.Query(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Row struct {
|
|
||||||
*sql.Row
|
|
||||||
// One of these two will be non-nil:
|
|
||||||
err error // deferred error for easy chaining
|
|
||||||
Mapper IMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Row) Scan(dest ...interface{}) error {
|
|
||||||
if row.err != nil {
|
|
||||||
return row.err
|
|
||||||
}
|
|
||||||
return row.Row.Scan(dest...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) QueryRow(query string, args ...interface{}) *Row {
|
|
||||||
row := db.DB.QueryRow(query, args...)
|
|
||||||
return &Row{row, nil, db.Mapper}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return &Row{nil, err, db.Mapper}
|
|
||||||
}
|
|
||||||
return db.QueryRow(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return &Row{nil, err, db.Mapper}
|
|
||||||
}
|
|
||||||
return db.QueryRow(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stmt struct {
|
|
||||||
*sql.Stmt
|
|
||||||
Mapper IMapper
|
|
||||||
names map[string]int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Prepare(query string) (*Stmt, error) {
|
|
||||||
names := make(map[string]int)
|
|
||||||
var i int
|
|
||||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
|
||||||
names[src[1:]] = i
|
|
||||||
i += 1
|
|
||||||
return "?"
|
|
||||||
})
|
|
||||||
|
|
||||||
stmt, err := db.DB.Prepare(query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Stmt{stmt, db.Mapper, names}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
|
|
||||||
vv := reflect.ValueOf(mp)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return nil, errors.New("mp should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
|
||||||
}
|
|
||||||
return s.Stmt.Exec(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
|
|
||||||
vv := reflect.ValueOf(st)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return nil, errors.New("mp should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
|
||||||
}
|
|
||||||
return s.Stmt.Exec(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
|
|
||||||
rows, err := s.Stmt.Query(args...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Rows{rows, s.Mapper}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
|
|
||||||
vv := reflect.ValueOf(mp)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return nil, errors.New("mp should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.Query(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
|
|
||||||
vv := reflect.ValueOf(st)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return nil, errors.New("mp should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.Query(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) QueryRow(args ...interface{}) *Row {
|
|
||||||
row := s.Stmt.QueryRow(args...)
|
|
||||||
return &Row{row, nil, s.Mapper}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) QueryRowMap(mp interface{}) *Row {
|
|
||||||
vv := reflect.ValueOf(mp)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return &Row{nil, errors.New("mp should be a map's pointer"), s.Mapper}
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.QueryRow(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stmt) QueryRowStruct(st interface{}) *Row {
|
|
||||||
vv := reflect.ValueOf(st)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return &Row{nil, errors.New("st should be a struct's pointer"), s.Mapper}
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]interface{}, len(s.names))
|
|
||||||
for k, i := range s.names {
|
|
||||||
args[i] = vv.Elem().FieldByName(k).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.QueryRow(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
re = regexp.MustCompile(`[?](\w+)`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// insert into (name) values (?)
|
|
||||||
// insert into (name) values (?name)
|
|
||||||
func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return db.DB.Exec(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return db.DB.Exec(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Rows struct {
|
|
||||||
*sql.Rows
|
|
||||||
Mapper IMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan data to a struct's pointer according field index
|
|
||||||
func (rs *Rows) ScanStruct(dest ...interface{}) error {
|
|
||||||
if len(dest) == 0 {
|
|
||||||
return errors.New("at least one struct")
|
|
||||||
}
|
|
||||||
|
|
||||||
vvvs := make([]reflect.Value, len(dest))
|
|
||||||
for i, s := range dest {
|
|
||||||
vv := reflect.ValueOf(s)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return errors.New("dest should be a struct's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
vvvs[i] = vv.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rs.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newDest := make([]interface{}, len(cols))
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
for _, vvv := range vvvs {
|
|
||||||
for j := 0; j < vvv.NumField(); j++ {
|
|
||||||
newDest[i] = vvv.Field(j).Addr().Interface()
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rs.Rows.Scan(newDest...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type EmptyScanner struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (EmptyScanner) Scan(src interface{}) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
fieldCache = make(map[reflect.Type]map[string]int)
|
|
||||||
fieldCacheMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
func fieldByName(v reflect.Value, name string) reflect.Value {
|
|
||||||
t := v.Type()
|
|
||||||
fieldCacheMutex.RLock()
|
|
||||||
cache, ok := fieldCache[t]
|
|
||||||
fieldCacheMutex.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
cache = make(map[string]int)
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
cache[t.Field(i).Name] = i
|
|
||||||
}
|
|
||||||
fieldCacheMutex.Lock()
|
|
||||||
fieldCache[t] = cache
|
|
||||||
fieldCacheMutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
if i, ok := cache[name]; ok {
|
|
||||||
return v.Field(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflect.Zero(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan data to a struct's pointer according field name
|
|
||||||
func (rs *Rows) ScanStruct2(dest interface{}) error {
|
|
||||||
vv := reflect.ValueOf(dest)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
|
|
||||||
return errors.New("dest should be a struct's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rs.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDest := make([]interface{}, len(cols))
|
|
||||||
var v EmptyScanner
|
|
||||||
for j, name := range cols {
|
|
||||||
f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
|
|
||||||
if f.IsValid() {
|
|
||||||
newDest[j] = f.Addr().Interface()
|
|
||||||
} else {
|
|
||||||
newDest[j] = &v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rs.Rows.Scan(newDest...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type cacheStruct struct {
|
|
||||||
value reflect.Value
|
|
||||||
idx int
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
reflectCache = make(map[reflect.Type]*cacheStruct)
|
|
||||||
reflectCacheMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
func ReflectNew(typ reflect.Type) reflect.Value {
|
|
||||||
reflectCacheMutex.RLock()
|
|
||||||
cs, ok := reflectCache[typ]
|
|
||||||
reflectCacheMutex.RUnlock()
|
|
||||||
|
|
||||||
const newSize = 200
|
|
||||||
|
|
||||||
if !ok || cs.idx+1 > newSize-1 {
|
|
||||||
cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), newSize, newSize), 0}
|
|
||||||
reflectCacheMutex.Lock()
|
|
||||||
reflectCache[typ] = cs
|
|
||||||
reflectCacheMutex.Unlock()
|
|
||||||
} else {
|
|
||||||
reflectCacheMutex.Lock()
|
|
||||||
cs.idx = cs.idx + 1
|
|
||||||
reflectCacheMutex.Unlock()
|
|
||||||
}
|
|
||||||
return cs.value.Index(cs.idx).Addr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan data to a slice's pointer, slice's length should equal to columns' number
|
|
||||||
func (rs *Rows) ScanSlice(dest interface{}) error {
|
|
||||||
vv := reflect.ValueOf(dest)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
|
|
||||||
return errors.New("dest should be a slice's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
vvv := vv.Elem()
|
|
||||||
cols, err := rs.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDest := make([]interface{}, len(cols))
|
|
||||||
|
|
||||||
for j := 0; j < len(cols); j++ {
|
|
||||||
if j >= vvv.Len() {
|
|
||||||
newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
|
|
||||||
} else {
|
|
||||||
newDest[j] = vvv.Index(j).Addr().Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rs.Rows.Scan(newDest...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
srcLen := vvv.Len()
|
|
||||||
for i := srcLen; i < len(cols); i++ {
|
|
||||||
vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan data to a map's pointer
|
|
||||||
func (rs *Rows) ScanMap(dest interface{}) error {
|
|
||||||
vv := reflect.ValueOf(dest)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return errors.New("dest should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rs.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDest := make([]interface{}, len(cols))
|
|
||||||
vvv := vv.Elem()
|
|
||||||
|
|
||||||
for i, _ := range cols {
|
|
||||||
newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
|
|
||||||
//v := reflect.New(vvv.Type().Elem())
|
|
||||||
//newDest[i] = v.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rs.Rows.Scan(newDest...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, name := range cols {
|
|
||||||
vname := reflect.ValueOf(name)
|
|
||||||
vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func (rs *Rows) ScanMap(dest interface{}) error {
|
|
||||||
vv := reflect.ValueOf(dest)
|
|
||||||
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
|
|
||||||
return errors.New("dest should be a map's pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rs.Columns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDest := make([]interface{}, len(cols))
|
|
||||||
err = rs.ScanSlice(newDest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
vvv := vv.Elem()
|
|
||||||
|
|
||||||
for i, name := range cols {
|
|
||||||
vname := reflect.ValueOf(name)
|
|
||||||
vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}*/
|
|
||||||
|
|
||||||
type Tx struct {
|
|
||||||
*sql.Tx
|
|
||||||
Mapper IMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Begin() (*Tx, error) {
|
|
||||||
tx, err := db.DB.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Tx{tx, db.Mapper}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) Prepare(query string) (*Stmt, error) {
|
|
||||||
names := make(map[string]int)
|
|
||||||
var i int
|
|
||||||
query = re.ReplaceAllStringFunc(query, func(src string) string {
|
|
||||||
names[src[1:]] = i
|
|
||||||
i += 1
|
|
||||||
return "?"
|
|
||||||
})
|
|
||||||
|
|
||||||
stmt, err := tx.Tx.Prepare(query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Stmt{stmt, tx.Mapper, names}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
|
|
||||||
// TODO:
|
|
||||||
return stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tx.Tx.Exec(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tx.Tx.Exec(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
|
|
||||||
rows, err := tx.Tx.Query(query, args...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Rows{rows, tx.Mapper}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tx.Query(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tx.Query(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
|
|
||||||
row := tx.Tx.QueryRow(query, args...)
|
|
||||||
return &Row{row, nil, tx.Mapper}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
|
|
||||||
query, args, err := MapToSlice(query, mp)
|
|
||||||
if err != nil {
|
|
||||||
return &Row{nil, err, tx.Mapper}
|
|
||||||
}
|
|
||||||
return tx.QueryRow(query, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
|
|
||||||
query, args, err := StructToSlice(query, st)
|
|
||||||
if err != nil {
|
|
||||||
return &Row{nil, err, tx.Mapper}
|
|
||||||
}
|
|
||||||
return tx.QueryRow(query, args...)
|
|
||||||
}
|
|
||||||
634
core/db_test.go
634
core/db_test.go
|
|
@ -1,634 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
createTableSqlite3 = "CREATE TABLE IF NOT EXISTS `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, " +
|
|
||||||
"`title` TEXT NULL, `age` FLOAT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL, `created` datetime);"
|
|
||||||
)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Id int64
|
|
||||||
Name string
|
|
||||||
Title string
|
|
||||||
Age float32
|
|
||||||
Alias string
|
|
||||||
NickName string
|
|
||||||
Created time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkOriQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var Id int64
|
|
||||||
var Name, Title, Alias, NickName string
|
|
||||||
var Age float32
|
|
||||||
var Created time.Time
|
|
||||||
err = rows.Scan(&Id, &Name, &Title, &Age, &Alias, &NickName, &Created)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
//fmt.Println(Id, Name, Title, Age, Alias, NickName)
|
|
||||||
}
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkStructQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?, ?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var user User
|
|
||||||
err = rows.ScanStruct(&user)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if user.Name != "xlw" {
|
|
||||||
fmt.Println(user)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkStruct2Query(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Mapper = NewCacheMapper(&SnakeMapper{})
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var user User
|
|
||||||
err = rows.ScanStruct2(&user)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if user.Name != "xlw" {
|
|
||||||
fmt.Println(user)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSliceInterfaceQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rows.Columns()
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
slice := make([]interface{}, len(cols))
|
|
||||||
err = rows.ScanSlice(&slice)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if slice[1].(string) != "xlw" {
|
|
||||||
fmt.Println(slice)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func BenchmarkSliceBytesQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rows.Columns()
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
slice := make([][]byte, len(cols))
|
|
||||||
err = rows.ScanSlice(&slice)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if string(slice[1]) != "xlw" {
|
|
||||||
fmt.Println(slice)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSliceStringQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name, created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cols, err := rows.Columns()
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
slice := make([]string, len(cols))
|
|
||||||
err = rows.ScanSlice(&slice)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if slice[1] != "xlw" {
|
|
||||||
fmt.Println(slice)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func BenchmarkMapInterfaceQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
m := make(map[string]interface{})
|
|
||||||
err = rows.ScanMap(&m)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if m["name"].(string) != "xlw" {
|
|
||||||
fmt.Println(m)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func BenchmarkMapBytesQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
m := make(map[string][]byte)
|
|
||||||
err = rows.ScanMap(&m)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if string(m["name"]) != "xlw" {
|
|
||||||
fmt.Println(m)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMapStringQuery(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
m := make(map[string]string)
|
|
||||||
err = rows.ScanMap(&m)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
if m["name"] != "xlw" {
|
|
||||||
fmt.Println(m)
|
|
||||||
b.Error(errors.New("name should be xlw"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.Close()
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func BenchmarkExec(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, err = db.Exec("insert into user (name, title, age, alias, nick_name,created) values (?,?,?,?,?,?)",
|
|
||||||
"xlw", "tester", 1.2, "lunny", "lunny xiao", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkExecMap(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
mp := map[string]interface{}{
|
|
||||||
"name": "xlw",
|
|
||||||
"title": "tester",
|
|
||||||
"age": 1.2,
|
|
||||||
"alias": "lunny",
|
|
||||||
"nick_name": "lunny xiao",
|
|
||||||
"created": time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, err = db.ExecMap(`insert into user (name, title, age, alias, nick_name, created)
|
|
||||||
values (?name,?title,?age,?alias,?nick_name,?created)`,
|
|
||||||
&mp)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExecMap(t *testing.T) {
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mp := map[string]interface{}{
|
|
||||||
"name": "xlw",
|
|
||||||
"title": "tester",
|
|
||||||
"age": 1.2,
|
|
||||||
"alias": "lunny",
|
|
||||||
"nick_name": "lunny xiao",
|
|
||||||
"created": time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.ExecMap(`insert into user (name, title, age, alias, nick_name,created)
|
|
||||||
values (?name,?title,?age,?alias,?nick_name,?created)`,
|
|
||||||
&mp)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := db.Query("select * from user")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var user User
|
|
||||||
err = rows.ScanStruct2(&user)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
fmt.Println("--", user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExecStruct(t *testing.T) {
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
user := User{Name: "xlw",
|
|
||||||
Title: "tester",
|
|
||||||
Age: 1.2,
|
|
||||||
Alias: "lunny",
|
|
||||||
NickName: "lunny xiao",
|
|
||||||
Created: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.ExecStruct(`insert into user (name, title, age, alias, nick_name,created)
|
|
||||||
values (?Name,?Title,?Age,?Alias,?NickName,?Created)`,
|
|
||||||
&user)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := db.QueryStruct("select * from user where name = ?Name", &user)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var user User
|
|
||||||
err = rows.ScanStruct2(&user)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
fmt.Println("1--", user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkExecStruct(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
os.Remove("./test.db")
|
|
||||||
db, err := Open("sqlite3", "./test.db")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSqlite3)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
user := User{Name: "xlw",
|
|
||||||
Title: "tester",
|
|
||||||
Age: 1.2,
|
|
||||||
Alias: "lunny",
|
|
||||||
NickName: "lunny xiao",
|
|
||||||
Created: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, err = db.ExecStruct(`insert into user (name, title, age, alias, nick_name,created)
|
|
||||||
values (?Name,?Title,?Age,?Alias,?NickName,?Created)`,
|
|
||||||
&user)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
144
core/dialect.go
144
core/dialect.go
|
|
@ -1,144 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type dbType string
|
|
||||||
|
|
||||||
type Uri struct {
|
|
||||||
DbType dbType
|
|
||||||
Proto string
|
|
||||||
Host string
|
|
||||||
Port string
|
|
||||||
DbName string
|
|
||||||
User string
|
|
||||||
Passwd string
|
|
||||||
Charset string
|
|
||||||
Laddr string
|
|
||||||
Raddr string
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// a dialect is a driver's wrapper
|
|
||||||
type Dialect interface {
|
|
||||||
Init(*Uri, string, string) error
|
|
||||||
URI() *Uri
|
|
||||||
DBType() dbType
|
|
||||||
SqlType(t *Column) string
|
|
||||||
SupportInsertMany() bool
|
|
||||||
QuoteStr() string
|
|
||||||
AutoIncrStr() string
|
|
||||||
SupportEngine() bool
|
|
||||||
SupportCharset() bool
|
|
||||||
IndexOnTable() bool
|
|
||||||
|
|
||||||
IndexCheckSql(tableName, idxName string) (string, []interface{})
|
|
||||||
TableCheckSql(tableName string) (string, []interface{})
|
|
||||||
ColumnCheckSql(tableName, colName string) (string, []interface{})
|
|
||||||
|
|
||||||
GetColumns(tableName string) ([]string, map[string]*Column, error)
|
|
||||||
GetTables() ([]*Table, error)
|
|
||||||
GetIndexes(tableName string) (map[string]*Index, error)
|
|
||||||
|
|
||||||
CreateTableSql(table *Table, tableName, storeEngine, charset string) string
|
|
||||||
Filters() []Filter
|
|
||||||
|
|
||||||
DriverName() string
|
|
||||||
DataSourceName() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Base struct {
|
|
||||||
dialect Dialect
|
|
||||||
driverName string
|
|
||||||
dataSourceName string
|
|
||||||
*Uri
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) Init(dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
|
|
||||||
b.dialect = dialect
|
|
||||||
b.driverName, b.dataSourceName = drivername, dataSourceName
|
|
||||||
b.Uri = uri
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) URI() *Uri {
|
|
||||||
return b.Uri
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) DBType() dbType {
|
|
||||||
return b.Uri.DbType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) DriverName() string {
|
|
||||||
return b.driverName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) DataSourceName() string {
|
|
||||||
return b.dataSourceName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) Quote(c string) string {
|
|
||||||
return b.dialect.QuoteStr() + c + b.dialect.QuoteStr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
|
|
||||||
var sql string
|
|
||||||
sql = "CREATE TABLE IF NOT EXISTS "
|
|
||||||
if tableName == "" {
|
|
||||||
tableName = table.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += b.Quote(tableName) + " ("
|
|
||||||
|
|
||||||
pkList := table.PrimaryKeys
|
|
||||||
|
|
||||||
for _, colName := range table.ColumnsSeq() {
|
|
||||||
col := table.GetColumn(colName)
|
|
||||||
if col.IsPrimaryKey && len(pkList) == 1 {
|
|
||||||
sql += col.String(b.dialect)
|
|
||||||
} else {
|
|
||||||
sql += col.StringNoPk(b.dialect)
|
|
||||||
}
|
|
||||||
sql = strings.TrimSpace(sql)
|
|
||||||
sql += ", "
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pkList) > 1 {
|
|
||||||
sql += "PRIMARY KEY ( "
|
|
||||||
sql += b.Quote(strings.Join(pkList, b.Quote(",")))
|
|
||||||
sql += " ), "
|
|
||||||
}
|
|
||||||
|
|
||||||
sql = sql[:len(sql)-2] + ")"
|
|
||||||
if b.dialect.SupportEngine() && storeEngine != "" {
|
|
||||||
sql += " ENGINE=" + storeEngine
|
|
||||||
}
|
|
||||||
if b.dialect.SupportCharset() {
|
|
||||||
if charset == "" {
|
|
||||||
charset = b.dialect.URI().Charset
|
|
||||||
}
|
|
||||||
sql += " DEFAULT CHARSET " + charset
|
|
||||||
}
|
|
||||||
sql += ";"
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
dialects = map[dbType]Dialect{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterDialect(dbName dbType, dialect Dialect) {
|
|
||||||
if dialect == nil {
|
|
||||||
panic("core: Register dialect is nil")
|
|
||||||
}
|
|
||||||
if _, dup := dialects[dbName]; dup {
|
|
||||||
panic("core: Register called twice for dialect " + dbName)
|
|
||||||
}
|
|
||||||
dialects[dbName] = dialect
|
|
||||||
}
|
|
||||||
|
|
||||||
func QueryDialect(dbName dbType) Dialect {
|
|
||||||
return dialects[dbName]
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
type driver interface {
|
|
||||||
Parse(string, string) (*Uri, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
drivers = map[string]driver{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterDriver(driverName string, driver driver) {
|
|
||||||
if driver == nil {
|
|
||||||
panic("core: Register driver is nil")
|
|
||||||
}
|
|
||||||
if _, dup := drivers[driverName]; dup {
|
|
||||||
panic("core: Register called twice for driver " + driverName)
|
|
||||||
}
|
|
||||||
drivers[driverName] = driver
|
|
||||||
}
|
|
||||||
|
|
||||||
func QueryDriver(driverName string) driver {
|
|
||||||
return drivers[driverName]
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Filter is an interface to filter SQL
|
|
||||||
type Filter interface {
|
|
||||||
Do(sql string, dialect Dialect, table *Table) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuoteFilter filter SQL replace ` to database's own quote character
|
|
||||||
type QuoteFilter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QuoteFilter) Do(sql string, dialect Dialect, table *Table) string {
|
|
||||||
return strings.Replace(sql, "`", dialect.QuoteStr(), -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IdFilter filter SQL replace (id) to primary key column name
|
|
||||||
type IdFilter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
type Quoter struct {
|
|
||||||
dialect Dialect
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewQuoter(dialect Dialect) *Quoter {
|
|
||||||
return &Quoter{dialect}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Quoter) Quote(content string) string {
|
|
||||||
return q.dialect.QuoteStr() + content + q.dialect.QuoteStr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string {
|
|
||||||
quoter := NewQuoter(dialect)
|
|
||||||
if table != nil && len(table.PrimaryKeys) == 1 {
|
|
||||||
sql = strings.Replace(sql, "`(id)`", quoter.Quote(table.PrimaryKeys[0]), -1)
|
|
||||||
sql = strings.Replace(sql, quoter.Quote("(id)"), quoter.Quote(table.PrimaryKeys[0]), -1)
|
|
||||||
return strings.Replace(sql, "(id)", quoter.Quote(table.PrimaryKeys[0]), -1)
|
|
||||||
}
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
const (
|
|
||||||
IndexType = iota + 1
|
|
||||||
UniqueType
|
|
||||||
)
|
|
||||||
|
|
||||||
// database index
|
|
||||||
type Index struct {
|
|
||||||
Name string
|
|
||||||
Type int
|
|
||||||
Cols []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// add columns which will be composite index
|
|
||||||
func (index *Index) AddColumn(cols ...string) {
|
|
||||||
for _, col := range cols {
|
|
||||||
index.Cols = append(index.Cols, col)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// new an index
|
|
||||||
func NewIndex(name string, indexType int) *Index {
|
|
||||||
return &Index{name, indexType, make([]string, 0)}
|
|
||||||
}
|
|
||||||
176
core/mapper.go
176
core/mapper.go
|
|
@ -1,176 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// name translation between struct, fields names and table, column names
|
|
||||||
type IMapper interface {
|
|
||||||
Obj2Table(string) string
|
|
||||||
Table2Obj(string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CacheMapper struct {
|
|
||||||
oriMapper IMapper
|
|
||||||
obj2tableCache map[string]string
|
|
||||||
obj2tableMutex sync.RWMutex
|
|
||||||
table2objCache map[string]string
|
|
||||||
table2objMutex sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCacheMapper(mapper IMapper) *CacheMapper {
|
|
||||||
return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string),
|
|
||||||
table2objCache: make(map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *CacheMapper) Obj2Table(o string) string {
|
|
||||||
m.obj2tableMutex.RLock()
|
|
||||||
t, ok := m.obj2tableCache[o]
|
|
||||||
m.obj2tableMutex.RUnlock()
|
|
||||||
if ok {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
t = m.oriMapper.Obj2Table(o)
|
|
||||||
m.obj2tableMutex.Lock()
|
|
||||||
m.obj2tableCache[o] = t
|
|
||||||
m.obj2tableMutex.Unlock()
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *CacheMapper) Table2Obj(t string) string {
|
|
||||||
m.table2objMutex.RLock()
|
|
||||||
o, ok := m.table2objCache[t]
|
|
||||||
m.table2objMutex.RUnlock()
|
|
||||||
if ok {
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
o = m.oriMapper.Table2Obj(t)
|
|
||||||
m.table2objMutex.Lock()
|
|
||||||
m.table2objCache[t] = o
|
|
||||||
m.table2objMutex.Unlock()
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// SameMapper implements IMapper and provides same name between struct and
|
|
||||||
// database table
|
|
||||||
type SameMapper struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m SameMapper) Obj2Table(o string) string {
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m SameMapper) Table2Obj(t string) string {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// SnakeMapper implements IMapper and provides name transaltion between
|
|
||||||
// struct and database table
|
|
||||||
type SnakeMapper struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func snakeCasedName(name string) string {
|
|
||||||
newstr := make([]rune, 0)
|
|
||||||
for idx, chr := range name {
|
|
||||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
|
||||||
if idx > 0 {
|
|
||||||
newstr = append(newstr, '_')
|
|
||||||
}
|
|
||||||
chr -= ('A' - 'a')
|
|
||||||
}
|
|
||||||
newstr = append(newstr, chr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(newstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func pascal2Sql(s string) (d string) {
|
|
||||||
d = ""
|
|
||||||
lastIdx := 0
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if s[i] >= 'A' && s[i] <= 'Z' {
|
|
||||||
if lastIdx < i {
|
|
||||||
d += s[lastIdx+1 : i]
|
|
||||||
}
|
|
||||||
if i != 0 {
|
|
||||||
d += "_"
|
|
||||||
}
|
|
||||||
d += string(s[i] + 32)
|
|
||||||
lastIdx = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d += s[lastIdx+1:]
|
|
||||||
return
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func (mapper SnakeMapper) Obj2Table(name string) string {
|
|
||||||
return snakeCasedName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func titleCasedName(name string) string {
|
|
||||||
newstr := make([]rune, 0)
|
|
||||||
upNextChar := true
|
|
||||||
|
|
||||||
name = strings.ToLower(name)
|
|
||||||
|
|
||||||
for _, chr := range name {
|
|
||||||
switch {
|
|
||||||
case upNextChar:
|
|
||||||
upNextChar = false
|
|
||||||
if 'a' <= chr && chr <= 'z' {
|
|
||||||
chr -= ('a' - 'A')
|
|
||||||
}
|
|
||||||
case chr == '_':
|
|
||||||
upNextChar = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
newstr = append(newstr, chr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(newstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mapper SnakeMapper) Table2Obj(name string) string {
|
|
||||||
return titleCasedName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// provide prefix table name support
|
|
||||||
type PrefixMapper struct {
|
|
||||||
Mapper IMapper
|
|
||||||
Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mapper PrefixMapper) Obj2Table(name string) string {
|
|
||||||
return mapper.Prefix + mapper.Mapper.Obj2Table(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mapper PrefixMapper) Table2Obj(name string) string {
|
|
||||||
return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):])
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper {
|
|
||||||
return PrefixMapper{mapper, prefix}
|
|
||||||
}
|
|
||||||
|
|
||||||
// provide suffix table name support
|
|
||||||
type SuffixMapper struct {
|
|
||||||
Mapper IMapper
|
|
||||||
Suffix string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mapper SuffixMapper) Obj2Table(name string) string {
|
|
||||||
return mapper.Suffix + mapper.Mapper.Obj2Table(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mapper SuffixMapper) Table2Obj(name string) string {
|
|
||||||
return mapper.Mapper.Table2Obj(name[len(mapper.Suffix):])
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSuffixMapper(mapper IMapper, suffix string) SuffixMapper {
|
|
||||||
return SuffixMapper{mapper, suffix}
|
|
||||||
}
|
|
||||||
25
core/pk.go
25
core/pk.go
|
|
@ -1,25 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PK []interface{}
|
|
||||||
|
|
||||||
func NewPK(pks ...interface{}) *PK {
|
|
||||||
p := PK(pks)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PK) ToString() (string, error) {
|
|
||||||
bs, err := json.Marshal(*p)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(bs), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PK) FromString(content string) error {
|
|
||||||
return json.Unmarshal([]byte(content), p)
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPK(t *testing.T) {
|
|
||||||
p := NewPK(1, 3, "string")
|
|
||||||
str, err := p.ToString()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
fmt.Println(str)
|
|
||||||
|
|
||||||
s := &PK{}
|
|
||||||
err = s.FromString(str)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
fmt.Println(s)
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// database table
|
|
||||||
type Table struct {
|
|
||||||
Name string
|
|
||||||
Type reflect.Type
|
|
||||||
columnsSeq []string
|
|
||||||
columns map[string]*Column
|
|
||||||
Indexes map[string]*Index
|
|
||||||
PrimaryKeys []string
|
|
||||||
AutoIncrement string
|
|
||||||
Created map[string]bool
|
|
||||||
Updated string
|
|
||||||
Version string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *Table) Columns() map[string]*Column {
|
|
||||||
return table.columns
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *Table) ColumnsSeq() []string {
|
|
||||||
return table.columnsSeq
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEmptyTable() *Table {
|
|
||||||
return &Table{columnsSeq: make([]string, 0),
|
|
||||||
columns: make(map[string]*Column),
|
|
||||||
Indexes: make(map[string]*Index),
|
|
||||||
Created: make(map[string]bool),
|
|
||||||
PrimaryKeys: make([]string, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTable(name string, t reflect.Type) *Table {
|
|
||||||
return &Table{Name: name, Type: t,
|
|
||||||
columnsSeq: make([]string, 0),
|
|
||||||
columns: make(map[string]*Column),
|
|
||||||
Indexes: make(map[string]*Index),
|
|
||||||
Created: make(map[string]bool),
|
|
||||||
PrimaryKeys: make([]string, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *Table) GetColumn(name string) *Column {
|
|
||||||
return table.columns[strings.ToLower(name)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// if has primary key, return column
|
|
||||||
func (table *Table) PKColumns() []*Column {
|
|
||||||
columns := make([]*Column, 0)
|
|
||||||
for _, name := range table.PrimaryKeys {
|
|
||||||
columns = append(columns, table.GetColumn(name))
|
|
||||||
}
|
|
||||||
return columns
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *Table) AutoIncrColumn() *Column {
|
|
||||||
return table.GetColumn(table.AutoIncrement)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *Table) VersionColumn() *Column {
|
|
||||||
return table.GetColumn(table.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a column to table
|
|
||||||
func (table *Table) AddColumn(col *Column) {
|
|
||||||
table.columnsSeq = append(table.columnsSeq, col.Name)
|
|
||||||
table.columns[strings.ToLower(col.Name)] = col
|
|
||||||
if col.IsPrimaryKey {
|
|
||||||
table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
|
|
||||||
}
|
|
||||||
if col.IsAutoIncrement {
|
|
||||||
table.AutoIncrement = col.Name
|
|
||||||
}
|
|
||||||
if col.IsCreated {
|
|
||||||
table.Created[col.Name] = true
|
|
||||||
}
|
|
||||||
if col.IsUpdated {
|
|
||||||
table.Updated = col.Name
|
|
||||||
}
|
|
||||||
if col.IsVersion {
|
|
||||||
table.Version = col.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add an index or an unique to table
|
|
||||||
func (table *Table) AddIndex(index *Index) {
|
|
||||||
table.Indexes[index.Name] = index
|
|
||||||
}
|
|
||||||
288
core/type.go
288
core/type.go
|
|
@ -1,288 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
POSTGRES = "postgres"
|
|
||||||
SQLITE = "sqlite3"
|
|
||||||
MYSQL = "mysql"
|
|
||||||
MSSQL = "mssql"
|
|
||||||
ORACLE = "oracle"
|
|
||||||
)
|
|
||||||
|
|
||||||
// xorm SQL types
|
|
||||||
type SQLType struct {
|
|
||||||
Name string
|
|
||||||
DefaultLength int
|
|
||||||
DefaultLength2 int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SQLType) IsText() bool {
|
|
||||||
return s.Name == Char || s.Name == Varchar || s.Name == TinyText ||
|
|
||||||
s.Name == Text || s.Name == MediumText || s.Name == LongText
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SQLType) IsBlob() bool {
|
|
||||||
return (s.Name == TinyBlob) || (s.Name == Blob) ||
|
|
||||||
s.Name == MediumBlob || s.Name == LongBlob ||
|
|
||||||
s.Name == Binary || s.Name == VarBinary || s.Name == Bytea
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
Bit = "BIT"
|
|
||||||
TinyInt = "TINYINT"
|
|
||||||
SmallInt = "SMALLINT"
|
|
||||||
MediumInt = "MEDIUMINT"
|
|
||||||
Int = "INT"
|
|
||||||
Integer = "INTEGER"
|
|
||||||
BigInt = "BIGINT"
|
|
||||||
|
|
||||||
Char = "CHAR"
|
|
||||||
Varchar = "VARCHAR"
|
|
||||||
TinyText = "TINYTEXT"
|
|
||||||
Text = "TEXT"
|
|
||||||
MediumText = "MEDIUMTEXT"
|
|
||||||
LongText = "LONGTEXT"
|
|
||||||
|
|
||||||
Date = "DATE"
|
|
||||||
DateTime = "DATETIME"
|
|
||||||
Time = "TIME"
|
|
||||||
TimeStamp = "TIMESTAMP"
|
|
||||||
TimeStampz = "TIMESTAMPZ"
|
|
||||||
|
|
||||||
Decimal = "DECIMAL"
|
|
||||||
Numeric = "NUMERIC"
|
|
||||||
|
|
||||||
Real = "REAL"
|
|
||||||
Float = "FLOAT"
|
|
||||||
Double = "DOUBLE"
|
|
||||||
|
|
||||||
Binary = "BINARY"
|
|
||||||
VarBinary = "VARBINARY"
|
|
||||||
TinyBlob = "TINYBLOB"
|
|
||||||
Blob = "BLOB"
|
|
||||||
MediumBlob = "MEDIUMBLOB"
|
|
||||||
LongBlob = "LONGBLOB"
|
|
||||||
Bytea = "BYTEA"
|
|
||||||
|
|
||||||
Bool = "BOOL"
|
|
||||||
|
|
||||||
Serial = "SERIAL"
|
|
||||||
BigSerial = "BIGSERIAL"
|
|
||||||
|
|
||||||
SqlTypes = map[string]bool{
|
|
||||||
Bit: true,
|
|
||||||
TinyInt: true,
|
|
||||||
SmallInt: true,
|
|
||||||
MediumInt: true,
|
|
||||||
Int: true,
|
|
||||||
Integer: true,
|
|
||||||
BigInt: true,
|
|
||||||
|
|
||||||
Char: true,
|
|
||||||
Varchar: true,
|
|
||||||
TinyText: true,
|
|
||||||
Text: true,
|
|
||||||
MediumText: true,
|
|
||||||
LongText: true,
|
|
||||||
|
|
||||||
Date: true,
|
|
||||||
DateTime: true,
|
|
||||||
Time: true,
|
|
||||||
TimeStamp: true,
|
|
||||||
TimeStampz: true,
|
|
||||||
|
|
||||||
Decimal: true,
|
|
||||||
Numeric: true,
|
|
||||||
|
|
||||||
Binary: true,
|
|
||||||
VarBinary: true,
|
|
||||||
Real: true,
|
|
||||||
Float: true,
|
|
||||||
Double: true,
|
|
||||||
TinyBlob: true,
|
|
||||||
Blob: true,
|
|
||||||
MediumBlob: true,
|
|
||||||
LongBlob: true,
|
|
||||||
Bytea: true,
|
|
||||||
|
|
||||||
Bool: true,
|
|
||||||
|
|
||||||
Serial: true,
|
|
||||||
BigSerial: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
intTypes = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
|
|
||||||
uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
|
|
||||||
)
|
|
||||||
|
|
||||||
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
|
|
||||||
var (
|
|
||||||
c_EMPTY_STRING string
|
|
||||||
c_BOOL_DEFAULT bool
|
|
||||||
c_BYTE_DEFAULT byte
|
|
||||||
c_COMPLEX64_DEFAULT complex64
|
|
||||||
c_COMPLEX128_DEFAULT complex128
|
|
||||||
c_FLOAT32_DEFAULT float32
|
|
||||||
c_FLOAT64_DEFAULT float64
|
|
||||||
c_INT64_DEFAULT int64
|
|
||||||
c_UINT64_DEFAULT uint64
|
|
||||||
c_INT32_DEFAULT int32
|
|
||||||
c_UINT32_DEFAULT uint32
|
|
||||||
c_INT16_DEFAULT int16
|
|
||||||
c_UINT16_DEFAULT uint16
|
|
||||||
c_INT8_DEFAULT int8
|
|
||||||
c_UINT8_DEFAULT uint8
|
|
||||||
c_INT_DEFAULT int
|
|
||||||
c_UINT_DEFAULT uint
|
|
||||||
c_TIME_DEFAULT time.Time
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
IntType = reflect.TypeOf(c_INT_DEFAULT)
|
|
||||||
Int8Type = reflect.TypeOf(c_INT8_DEFAULT)
|
|
||||||
Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
|
|
||||||
Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
|
|
||||||
Int64Type = reflect.TypeOf(c_INT64_DEFAULT)
|
|
||||||
|
|
||||||
UintType = reflect.TypeOf(c_UINT_DEFAULT)
|
|
||||||
Uint8Type = reflect.TypeOf(c_UINT8_DEFAULT)
|
|
||||||
Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
|
|
||||||
Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
|
|
||||||
Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)
|
|
||||||
|
|
||||||
Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
|
|
||||||
Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)
|
|
||||||
|
|
||||||
Complex64Type = reflect.TypeOf(c_COMPLEX64_DEFAULT)
|
|
||||||
Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)
|
|
||||||
|
|
||||||
StringType = reflect.TypeOf(c_EMPTY_STRING)
|
|
||||||
BoolType = reflect.TypeOf(c_BOOL_DEFAULT)
|
|
||||||
ByteType = reflect.TypeOf(c_BYTE_DEFAULT)
|
|
||||||
|
|
||||||
TimeType = reflect.TypeOf(c_TIME_DEFAULT)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
PtrIntType = reflect.PtrTo(IntType)
|
|
||||||
PtrInt8Type = reflect.PtrTo(Int8Type)
|
|
||||||
PtrInt16Type = reflect.PtrTo(Int16Type)
|
|
||||||
PtrInt32Type = reflect.PtrTo(Int32Type)
|
|
||||||
PtrInt64Type = reflect.PtrTo(Int64Type)
|
|
||||||
|
|
||||||
PtrUintType = reflect.PtrTo(UintType)
|
|
||||||
PtrUint8Type = reflect.PtrTo(Uint8Type)
|
|
||||||
PtrUint16Type = reflect.PtrTo(Uint16Type)
|
|
||||||
PtrUint32Type = reflect.PtrTo(Uint32Type)
|
|
||||||
PtrUint64Type = reflect.PtrTo(Uint64Type)
|
|
||||||
|
|
||||||
PtrFloat32Type = reflect.PtrTo(Float32Type)
|
|
||||||
PtrFloat64Type = reflect.PtrTo(Float64Type)
|
|
||||||
|
|
||||||
PtrComplex64Type = reflect.PtrTo(Complex64Type)
|
|
||||||
PtrComplex128Type = reflect.PtrTo(Complex128Type)
|
|
||||||
|
|
||||||
PtrStringType = reflect.PtrTo(StringType)
|
|
||||||
PtrBoolType = reflect.PtrTo(BoolType)
|
|
||||||
PtrByteType = reflect.PtrTo(ByteType)
|
|
||||||
|
|
||||||
PtrTimeType = reflect.PtrTo(TimeType)
|
|
||||||
)
|
|
||||||
|
|
||||||
func Type2SQLType(t reflect.Type) (st SQLType) {
|
|
||||||
|
|
||||||
switch k := t.Kind(); k {
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
|
||||||
st = SQLType{Int, 0, 0}
|
|
||||||
case reflect.Int64, reflect.Uint64:
|
|
||||||
st = SQLType{BigInt, 0, 0}
|
|
||||||
case reflect.Float32:
|
|
||||||
st = SQLType{Float, 0, 0}
|
|
||||||
case reflect.Float64:
|
|
||||||
st = SQLType{Double, 0, 0}
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
st = SQLType{Varchar, 64, 0}
|
|
||||||
case reflect.Array, reflect.Slice, reflect.Map:
|
|
||||||
if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
|
|
||||||
st = SQLType{Blob, 0, 0}
|
|
||||||
} else {
|
|
||||||
st = SQLType{Text, 0, 0}
|
|
||||||
}
|
|
||||||
case reflect.Bool:
|
|
||||||
st = SQLType{Bool, 0, 0}
|
|
||||||
case reflect.String:
|
|
||||||
st = SQLType{Varchar, 255, 0}
|
|
||||||
case reflect.Struct:
|
|
||||||
if t == reflect.TypeOf(c_TIME_DEFAULT) {
|
|
||||||
st = SQLType{DateTime, 0, 0}
|
|
||||||
} else {
|
|
||||||
// TODO need to handle association struct
|
|
||||||
st = SQLType{Text, 0, 0}
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
st, _ = ptrType2SQLType(t)
|
|
||||||
default:
|
|
||||||
st = SQLType{Text, 0, 0}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ptrType2SQLType(t reflect.Type) (st SQLType, has bool) {
|
|
||||||
has = true
|
|
||||||
|
|
||||||
switch t {
|
|
||||||
case reflect.TypeOf(&c_EMPTY_STRING):
|
|
||||||
st = SQLType{Varchar, 255, 0}
|
|
||||||
return
|
|
||||||
case reflect.TypeOf(&c_BOOL_DEFAULT):
|
|
||||||
st = SQLType{Bool, 0, 0}
|
|
||||||
case reflect.TypeOf(&c_COMPLEX64_DEFAULT), reflect.TypeOf(&c_COMPLEX128_DEFAULT):
|
|
||||||
st = SQLType{Varchar, 64, 0}
|
|
||||||
case reflect.TypeOf(&c_FLOAT32_DEFAULT):
|
|
||||||
st = SQLType{Float, 0, 0}
|
|
||||||
case reflect.TypeOf(&c_FLOAT64_DEFAULT):
|
|
||||||
st = SQLType{Double, 0, 0}
|
|
||||||
case reflect.TypeOf(&c_INT64_DEFAULT), reflect.TypeOf(&c_UINT64_DEFAULT):
|
|
||||||
st = SQLType{BigInt, 0, 0}
|
|
||||||
case reflect.TypeOf(&c_TIME_DEFAULT):
|
|
||||||
st = SQLType{DateTime, 0, 0}
|
|
||||||
case reflect.TypeOf(&c_INT_DEFAULT), reflect.TypeOf(&c_INT32_DEFAULT), reflect.TypeOf(&c_INT8_DEFAULT), reflect.TypeOf(&c_INT16_DEFAULT), reflect.TypeOf(&c_UINT_DEFAULT), reflect.TypeOf(&c_UINT32_DEFAULT), reflect.TypeOf(&c_UINT8_DEFAULT), reflect.TypeOf(&c_UINT16_DEFAULT):
|
|
||||||
st = SQLType{Int, 0, 0}
|
|
||||||
default:
|
|
||||||
has = false
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// default sql type change to go types
|
|
||||||
func SQLType2Type(st SQLType) reflect.Type {
|
|
||||||
name := strings.ToUpper(st.Name)
|
|
||||||
switch name {
|
|
||||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
|
|
||||||
return reflect.TypeOf(1)
|
|
||||||
case BigInt, BigSerial:
|
|
||||||
return reflect.TypeOf(int64(1))
|
|
||||||
case Float, Real:
|
|
||||||
return reflect.TypeOf(float32(1))
|
|
||||||
case Double:
|
|
||||||
return reflect.TypeOf(float64(1))
|
|
||||||
case Char, Varchar, TinyText, Text, MediumText, LongText:
|
|
||||||
return reflect.TypeOf("")
|
|
||||||
case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
|
|
||||||
return reflect.TypeOf([]byte{})
|
|
||||||
case Bool:
|
|
||||||
return reflect.TypeOf(true)
|
|
||||||
case DateTime, Date, Time, TimeStamp, TimeStampz:
|
|
||||||
return reflect.TypeOf(c_TIME_DEFAULT)
|
|
||||||
case Decimal, Numeric:
|
|
||||||
return reflect.TypeOf("")
|
|
||||||
default:
|
|
||||||
return reflect.TypeOf("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4
doc.go
4
doc.go
|
|
@ -9,7 +9,7 @@ Installation
|
||||||
|
|
||||||
Make sure you have installed Go 1.1+ and then:
|
Make sure you have installed Go 1.1+ and then:
|
||||||
|
|
||||||
go get github.com/lunny/xorm
|
go get github.com/go-xorm/xorm
|
||||||
|
|
||||||
Create Engine
|
Create Engine
|
||||||
|
|
||||||
|
|
@ -137,6 +137,6 @@ The above 7 methods could use with condition methods.
|
||||||
engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find()
|
engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find()
|
||||||
//SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
|
//SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
|
||||||
|
|
||||||
More usage, please visit https://github.com/lunny/xorm/blob/master/docs/QuickStartEn.md
|
More usage, please visit https://github.com/go-xorm/xorm/blob/master/docs/QuickStartEn.md
|
||||||
*/
|
*/
|
||||||
package xorm
|
package xorm
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
* **v0.2.3** : Improved documents; Optimistic Locking support; Timestamp with time zone support; Mapper change to tableMapper and columnMapper & added PrefixMapper & SuffixMapper support custom table or column name's prefix and suffix;Insert now return affected, err instead of id, err; Added UseBool & Distinct;
|
* **v0.2.3** : Improved documents; Optimistic Locking support; Timestamp with time zone support; Mapper change to tableMapper and columnMapper & added PrefixMapper & SuffixMapper support custom table or column name's prefix and suffix;Insert now return affected, err instead of id, err; Added UseBool & Distinct;
|
||||||
* **v0.2.2** : Postgres drivers now support lib/pq; Added method Iterate for record by record to handler;Added SetMaxConns(go1.2+) support; some bugs fixed.
|
* **v0.2.2** : Postgres drivers now support lib/pq; Added method Iterate for record by record to handler;Added SetMaxConns(go1.2+) support; some bugs fixed.
|
||||||
* **v0.2.1** : Added database reverse tool, now support generate go & c++ codes, see [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md); some bug fixed.
|
* **v0.2.1** : Added database reverse tool, now support generate go & c++ codes, see [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); some bug fixed.
|
||||||
* **v0.2.0** : Added Cache supported, select is speeder up 3~5x; Added SameMapper for same name between struct and table; Added Sync method for auto added tables, columns, indexes;
|
* **v0.2.0** : Added Cache supported, select is speeder up 3~5x; Added SameMapper for same name between struct and table; Added Sync method for auto added tables, columns, indexes;
|
||||||
* **v0.1.9** : Added postgres and mymysql supported; Added ` and ? supported on Raw SQL even if postgres; Added Cols, StoreEngine, Charset function, Added many column data type supported, please see [Mapping Rules](#mapping).
|
* **v0.1.9** : Added postgres and mymysql supported; Added ` and ? supported on Raw SQL even if postgres; Added Cols, StoreEngine, Charset function, Added many column data type supported, please see [Mapping Rules](#mapping).
|
||||||
* **v0.1.8** : Added union index and union unique supported, please see [Mapping Rules](#mapping).
|
* **v0.1.8** : Added union index and union unique supported, please see [Mapping Rules](#mapping).
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@
|
||||||
|
|
||||||
* **v0.2.3** : 改善了文档;提供了乐观锁支持;添加了带时区时间字段支持;Mapper现在分成表名Mapper和字段名Mapper,同时实现了表或字段的自定义前缀后缀;Insert方法的返回值含义从id, err更改为 affected, err,请大家注意;添加了UseBool 和 Distinct函数。
|
* **v0.2.3** : 改善了文档;提供了乐观锁支持;添加了带时区时间字段支持;Mapper现在分成表名Mapper和字段名Mapper,同时实现了表或字段的自定义前缀后缀;Insert方法的返回值含义从id, err更改为 affected, err,请大家注意;添加了UseBool 和 Distinct函数。
|
||||||
* **v0.2.2** : Postgres驱动新增了对lib/pq的支持;新增了逐条遍历方法Iterate;新增了SetMaxConns(go1.2+)支持,修复了bug若干;
|
* **v0.2.2** : Postgres驱动新增了对lib/pq的支持;新增了逐条遍历方法Iterate;新增了SetMaxConns(go1.2+)支持,修复了bug若干;
|
||||||
* **v0.2.1** : 新增数据库反转工具,当前支持go和c++代码的生成,详见 [Xorm Tool README](https://github.com/lunny/xorm/blob/master/xorm/README.md); 修复了一些bug.
|
* **v0.2.1** : 新增数据库反转工具,当前支持go和c++代码的生成,详见 [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); 修复了一些bug.
|
||||||
* **v0.2.0** : 新增 [缓存](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#120)支持,查询速度提升3-5倍; 新增数据库表和Struct同名的映射方式; 新增Sync同步表结构;
|
* **v0.2.0** : 新增 [缓存](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#120)支持,查询速度提升3-5倍; 新增数据库表和Struct同名的映射方式; 新增Sync同步表结构;
|
||||||
* **v0.1.9** : 新增 postgres 和 mymysql 驱动支持; 在Postgres中支持原始SQL语句中使用 ` 和 ? 符号; 新增Cols, StoreEngine, Charset 函数;SQL语句打印支持io.Writer接口,默认打印到控制台;新增更多的字段类型支持,详见 [映射规则](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#21);删除废弃的MakeSession和Create函数。
|
* **v0.1.9** : 新增 postgres 和 mymysql 驱动支持; 在Postgres中支持原始SQL语句中使用 ` 和 ? 符号; 新增Cols, StoreEngine, Charset 函数;SQL语句打印支持io.Writer接口,默认打印到控制台;新增更多的字段类型支持,详见 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#21);删除废弃的MakeSession和Create函数。
|
||||||
* **v0.1.8** : 新增联合index,联合unique支持,请查看 [映射规则](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md#21)。
|
* **v0.1.8** : 新增联合index,联合unique支持,请查看 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#21)。
|
||||||
* **v0.1.7** : 新增IConnectPool接口以及NoneConnectPool, SysConnectPool, SimpleConnectPool三种实现,可以选择不使用连接池,使用系统连接池和使用自带连接池三种实现,默认为SysConnectPool,即系统自带的连接池。同时支持自定义连接池。Engine新增Close方法,在系统退出时应调用此方法。
|
* **v0.1.7** : 新增IConnectPool接口以及NoneConnectPool, SysConnectPool, SimpleConnectPool三种实现,可以选择不使用连接池,使用系统连接池和使用自带连接池三种实现,默认为SysConnectPool,即系统自带的连接池。同时支持自定义连接池。Engine新增Close方法,在系统退出时应调用此方法。
|
||||||
* **v0.1.6** : 新增Conversion,支持自定义类型到数据库类型的转换;新增查询结构体自动检测匿名成员支持;新增单向映射支持;
|
* **v0.1.6** : 新增Conversion,支持自定义类型到数据库类型的转换;新增查询结构体自动检测匿名成员支持;新增单向映射支持;
|
||||||
* **v0.1.5** : 新增对多线程的支持;新增Sql()函数;支持任意sql语句的struct查询;Get函数返回值变动;MakeSession和Create函数被NewSession和NewEngine函数替代;
|
* **v0.1.5** : 新增对多线程的支持;新增Sql()函数;支持任意sql语句的struct查询;Get函数返回值变动;MakeSession和Create函数被NewSession和NewEngine函数替代;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ xorm 快速入门
|
||||||
* [1.创建Orm引擎](#10)
|
* [1.创建Orm引擎](#10)
|
||||||
* [2.定义表结构体](#20)
|
* [2.定义表结构体](#20)
|
||||||
* [2.1.名称映射规则](#21)
|
* [2.1.名称映射规则](#21)
|
||||||
* [2.2.前缀映射规则和后缀映射规则](#22)
|
* [2.2.前缀映射,后缀映射和缓存映射](#22)
|
||||||
* [2.3.使用Table和Tag改变名称映射](#23)
|
* [2.3.使用Table和Tag改变名称映射](#23)
|
||||||
* [2.4.Column属性定义](#24)
|
* [2.4.Column属性定义](#24)
|
||||||
* [2.5.Go与字段类型对应表](#25)
|
* [2.5.Go与字段类型对应表](#25)
|
||||||
|
|
@ -29,12 +29,13 @@ xorm 快速入门
|
||||||
* [9.执行SQL命令](#100)
|
* [9.执行SQL命令](#100)
|
||||||
* [10.事务处理](#110)
|
* [10.事务处理](#110)
|
||||||
* [11.缓存](#120)
|
* [11.缓存](#120)
|
||||||
* [12.xorm工具](#130)
|
* [12.事件](#125)
|
||||||
* [12.1.反转命令](#131)
|
* [13.xorm工具](#130)
|
||||||
* [13.Examples](#140)
|
* [13.1.反转命令](#131)
|
||||||
* [14.案例](#150)
|
* [14.Examples](#140)
|
||||||
* [15.那些年我们踩过的坑](#160)
|
* [15.案例](#150)
|
||||||
* [16.讨论](#170)
|
* [16.那些年我们踩过的坑](#160)
|
||||||
|
* [17.讨论](#170)
|
||||||
|
|
||||||
<a name="10" id="10"></a>
|
<a name="10" id="10"></a>
|
||||||
## 1.创建Orm引擎
|
## 1.创建Orm引擎
|
||||||
|
|
@ -44,7 +45,7 @@ xorm 快速入门
|
||||||
```Go
|
```Go
|
||||||
import (
|
import (
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
|
engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
@ -55,7 +56,7 @@ or
|
||||||
```Go
|
```Go
|
||||||
import (
|
import (
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
engine, err = xorm.NewEngine("sqlite3", "./test.db")
|
engine, err = xorm.NewEngine("sqlite3", "./test.db")
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
@ -64,8 +65,11 @@ defer engine.Close()
|
||||||
一般如果只针对一个数据库进行操作,只需要创建一个Engine即可。Engine支持在多GoRutine下使用。
|
一般如果只针对一个数据库进行操作,只需要创建一个Engine即可。Engine支持在多GoRutine下使用。
|
||||||
|
|
||||||
xorm当前支持五种驱动四个数据库如下:
|
xorm当前支持五种驱动四个数据库如下:
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL)
|
* Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL)
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||||
|
|
||||||
|
|
@ -120,27 +124,39 @@ engine.SetMapper(SameMapper{})
|
||||||
|
|
||||||
同时需要注意的是:
|
同时需要注意的是:
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||||
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
|
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
|
||||||
|
|
||||||
|
=======
|
||||||
|
* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||||
|
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
|
||||||
|
|
||||||
|
>>>>>>> master
|
||||||
```Go
|
```Go
|
||||||
engine.SetTableMapper(SameMapper{})
|
engine.SetTableMapper(SameMapper{})
|
||||||
engine.SetColumnMapper(SnakeMapper{})
|
engine.SetColumnMapper(SnakeMapper{})
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="22" id="22"></a>
|
<a name="22" id="22"></a>
|
||||||
### 2.2.前缀映射规则和后缀映射规则
|
### 2.2.前缀映射,后缀映射和缓存映射
|
||||||
|
|
||||||
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
||||||
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
||||||
|
<<<<<<< HEAD
|
||||||
*
|
*
|
||||||
|
=======
|
||||||
|
* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以组合其它的映射规则,起到在内存中缓存曾经映射过的命名映射。
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
<a name="23" id="23"></a>
|
<a name="23" id="23"></a>
|
||||||
### 2.3.使用Table和Tag改变名称映射
|
### 2.3.使用Table和Tag改变名称映射
|
||||||
|
|
||||||
如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。
|
如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。
|
||||||
|
|
||||||
通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。
|
* 如果struct拥有`Tablename() string`的成员方法,那么此方法的返回值即是该struct默认对应的数据库表名。
|
||||||
|
|
||||||
|
* 通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。
|
||||||
|
|
||||||
<a name="23" id="23"></a>
|
<a name="23" id="23"></a>
|
||||||
### 2.4.Column属性定义
|
### 2.4.Column属性定义
|
||||||
|
|
@ -153,7 +169,7 @@ type User struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。
|
对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。对于使用者,一般只要使用自己熟悉的数据库字段定义即可。
|
||||||
|
|
||||||
具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写:
|
具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写:
|
||||||
|
|
||||||
|
|
@ -165,7 +181,7 @@ type User struct {
|
||||||
<td>pk</td><td>是否是Primary Key,如果在一个struct中有多个字段都使用了此标记,则这多个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7种Go的数据类型,复合主键支持这7种Go的数据类型的组合。</td>
|
<td>pk</td><td>是否是Primary Key,如果在一个struct中有多个字段都使用了此标记,则这多个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7种Go的数据类型,复合主键支持这7种Go的数据类型的组合。</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)</td><td>字段类型</td>
|
<td>当前支持30多种字段类型,详情参见 [字段类型](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)</td><td>字段类型</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>autoincr</td><td>是否是自增</td>
|
<td>autoincr</td><td>是否是自增</td>
|
||||||
|
|
@ -211,7 +227,7 @@ type User struct {
|
||||||
|
|
||||||
- 2.string类型默认映射为varchar(255),如果需要不同的定义,可以在tag中自定义
|
- 2.string类型默认映射为varchar(255),如果需要不同的定义,可以在tag中自定义
|
||||||
|
|
||||||
- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。具体参见 [go类型<->数据库类型对应表](https://github.com/lunny/xorm/blob/master/docs/AutoMap.md)
|
- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。具体参见 [go类型<->数据库类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/AutoMap.md)
|
||||||
|
|
||||||
- 4.实现了Conversion接口的类型或者结构体,将根据接口的转换方式在类型和数据库记录之间进行相互转换。
|
- 4.实现了Conversion接口的类型或者结构体,将根据接口的转换方式在类型和数据库记录之间进行相互转换。
|
||||||
```Go
|
```Go
|
||||||
|
|
@ -226,7 +242,7 @@ type Conversion interface {
|
||||||
|
|
||||||
如果不使用tag来定义field对应的数据库字段类型,那么系统会自动给出一个默认的字段类型,对应表如下:
|
如果不使用tag来定义field对应的数据库字段类型,那么系统会自动给出一个默认的字段类型,对应表如下:
|
||||||
|
|
||||||
[go类型<->数据库类型对应表](https://github.com/lunny/xorm/blob/master/docs/AutoMap.md)
|
[go类型<->数据库类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/AutoMap.md)
|
||||||
|
|
||||||
<a name="30" id="30"></a>
|
<a name="30" id="30"></a>
|
||||||
## 3.表结构操作
|
## 3.表结构操作
|
||||||
|
|
@ -407,7 +423,11 @@ engine.Cols("age", "name").Update(&user)
|
||||||
// UPDATE user SET age=? AND name=?
|
// UPDATE user SET age=? AND name=?
|
||||||
```
|
```
|
||||||
|
|
||||||
其中的参数"age", "name"也可以写成"age, name",两种写法均可
|
* AllCols()
|
||||||
|
查询或更新所有字段。
|
||||||
|
|
||||||
|
* MustCols(…string)
|
||||||
|
某些字段必须更新。
|
||||||
|
|
||||||
* Omit(...string)
|
* Omit(...string)
|
||||||
和cols相反,此函数指定排除某些指定的字段。注意:此方法和Cols方法不可同时使用
|
和cols相反,此函数指定排除某些指定的字段。注意:此方法和Cols方法不可同时使用
|
||||||
|
|
@ -578,13 +598,21 @@ affected, err := engine.Id(id).Update(user)
|
||||||
|
|
||||||
这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择:
|
这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择:
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
1. 通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。
|
1. 通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。
|
||||||
|
=======
|
||||||
|
* 1.通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
affected, err := engine.Id(id).Cols("age").Update(&user)
|
affected, err := engine.Id(id).Cols("age").Update(&user)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
2. 通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。
|
2. 通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。
|
||||||
|
=======
|
||||||
|
* 2.通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0})
|
affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0})
|
||||||
|
|
@ -681,6 +709,8 @@ if err != nil {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* 注意如果您使用的是mysql,数据库引擎为innodb事务才有效,myisam引擎是不支持事务的。
|
||||||
|
|
||||||
<a name="120" id="120"></a>
|
<a name="120" id="120"></a>
|
||||||
## 11.缓存
|
## 11.缓存
|
||||||
|
|
||||||
|
|
@ -725,22 +755,48 @@ engine.ClearCache(new(User))
|
||||||
|
|
||||||
缓存的实现原理如下图所示:
|
缓存的实现原理如下图所示:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
<a name="125" id="125"></a>
|
||||||
|
## 12.事件
|
||||||
|
xorm支持两种方式的事件,一种是在Struct中的特定方法来作为事件的方法,一种是在执行语句的过程中执行事件。
|
||||||
|
|
||||||
|
在Struct中作为成员方法的事件如下:
|
||||||
|
|
||||||
|
* BeforeInsert()
|
||||||
|
|
||||||
|
* BeforeUpdate()
|
||||||
|
|
||||||
|
* BeforeDelete()
|
||||||
|
|
||||||
|
* AfterInsert()
|
||||||
|
|
||||||
|
* AfterUpdate()
|
||||||
|
|
||||||
|
* AfterDelete()
|
||||||
|
|
||||||
|
在语句执行过程中的事件方法为:
|
||||||
|
|
||||||
|
* Before(beforeFunc interface{})
|
||||||
|
|
||||||
|
* After(afterFunc interface{})
|
||||||
|
|
||||||
|
其中beforeFunc和afterFunc的原型为func(bean interface{}).
|
||||||
|
|
||||||
<a name="130" id="130"></a>
|
<a name="130" id="130"></a>
|
||||||
## 12.xorm工具
|
## 13.xorm工具
|
||||||
xorm工具提供了xorm命令,能够帮助做很多事情。
|
xorm工具提供了xorm命令,能够帮助做很多事情。
|
||||||
|
|
||||||
### 12.1.反转命令
|
### 13.1.反转命令
|
||||||
参见 [xorm工具](https://github.com/lunny/xorm/tree/master/xorm)
|
参见 [xorm工具](https://github.com/go-xorm/xorm/tree/master/xorm)
|
||||||
|
|
||||||
<a name="140" id="140"></a>
|
<a name="140" id="140"></a>
|
||||||
## 13.Examples
|
## 14.Examples
|
||||||
|
|
||||||
请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples)
|
请访问[https://github.com/go-xorm/xorm/tree/master/examples](https://github.com/go-xorm/xorm/tree/master/examples)
|
||||||
|
|
||||||
<a name="150" id="150"></a>
|
<a name="150" id="150"></a>
|
||||||
## 14.案例
|
## 15.案例
|
||||||
|
|
||||||
* [Gowalker](http://gowalker.org),源代码 [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
* [Gowalker](http://gowalker.org),源代码 [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
|
||||||
|
|
||||||
|
|
@ -751,7 +807,7 @@ xorm工具提供了xorm命令,能够帮助做很多事情。
|
||||||
* [VeryHour](http://veryhour.com)
|
* [VeryHour](http://veryhour.com)
|
||||||
|
|
||||||
<a name="160" id="160"></a>
|
<a name="160" id="160"></a>
|
||||||
## 15.那些年我们踩过的坑
|
## 16.那些年我们踩过的坑
|
||||||
* 怎么同时使用xorm的tag和json的tag?
|
* 怎么同时使用xorm的tag和json的tag?
|
||||||
|
|
||||||
答:使用空格
|
答:使用空格
|
||||||
|
|
@ -795,5 +851,5 @@ money float64 `xorm:"Numeric"`
|
||||||
|
|
||||||
|
|
||||||
<a name="170" id="170"></a>
|
<a name="170" id="170"></a>
|
||||||
## 16.讨论
|
## 17.讨论
|
||||||
请加入QQ群:280360085 进行讨论。
|
请加入QQ群:280360085 进行讨论。
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ When using xorm, you can create multiple orm engines, an engine means a databse.
|
||||||
```Go
|
```Go
|
||||||
import (
|
import (
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
|
engine, err := xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
@ -52,7 +52,7 @@ or
|
||||||
```Go
|
```Go
|
||||||
import (
|
import (
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
engine, err = xorm.NewEngine("sqlite3", "./test.db")
|
engine, err = xorm.NewEngine("sqlite3", "./test.db")
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
@ -100,30 +100,47 @@ engine.Logger = f
|
||||||
<a name="20" id="20"></a>
|
<a name="20" id="20"></a>
|
||||||
## 2.Define struct
|
## 2.Define struct
|
||||||
|
|
||||||
xorm支持将一个struct映射为数据库中对应的一张表。映射规则如下:
|
xorm map a struct to a database table, the rule is below.
|
||||||
|
|
||||||
<a name="21" id="21"></a>
|
<a name="21" id="21"></a>
|
||||||
### 2.1.名称映射规则
|
### 2.1.name mapping rule
|
||||||
|
|
||||||
名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射。由xorm.IMapper接口的实现者来管理,xorm内置了两种IMapper实现:`SnakeMapper` 和 `SameMapper`。SnakeMapper支持struct为驼峰式命名,表结构为下划线命名之间的转换;SameMapper支持相同的命名。
|
use xorm.IMapper interface to implement. There are two IMapper implemented: `SnakeMapper` and `SameMapper`. SnakeMapper means struct name is word by word and table name or column name as 下划线. SameMapper means same name between struct and table.
|
||||||
|
|
||||||
当前SnakeMapper为默认值,如果需要改变时,在engine创建完成后使用
|
SnakeMapper is the default.
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
engine.Mapper = SameMapper{}
|
engine.Mapper = SameMapper{}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
同时需要注意的是:
|
||||||
|
|
||||||
|
* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||||
|
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
engine.SetTableMapper(SameMapper{})
|
||||||
|
engine.SetColumnMapper(SnakeMapper{})
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="22" id="22"></a>
|
||||||
|
### 2.2.前缀映射规则,后缀映射规则和缓存映射规则
|
||||||
|
|
||||||
|
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
||||||
|
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀,当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
|
||||||
|
* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以起到在内存中缓存曾经映射过的命名映射。
|
||||||
|
|
||||||
当然,如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
当然,如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||||
|
|
||||||
<a name="22" id="22"></a>
|
<a name="22" id="22"></a>
|
||||||
### 2.2.使用Table和Tag改变名称映射
|
### 2.3.使用Table和Tag改变名称映射
|
||||||
|
|
||||||
如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。
|
如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。
|
||||||
|
|
||||||
通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。
|
通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。
|
||||||
|
|
||||||
<a name="23" id="23"></a>
|
<a name="23" id="23"></a>
|
||||||
### 2.3.Column属性定义
|
### 2.4.Column属性定义
|
||||||
我们在field对应的Tag中对Column的一些属性进行定义,定义的方法基本和我们写SQL定义表结构类似,比如:
|
我们在field对应的Tag中对Column的一些属性进行定义,定义的方法基本和我们写SQL定义表结构类似,比如:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -133,7 +150,7 @@ type User struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。
|
对于不同的数据库系统,数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义,基本的原则是尽量兼容各种数据库的字段类型,具体的字段对应关系可以查看[字段类型对应表](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)。
|
||||||
|
|
||||||
具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写:
|
具体的映射规则如下,另Tag中的关键字均不区分大小写,字段名区分大小写:
|
||||||
|
|
||||||
|
|
@ -145,7 +162,7 @@ type User struct {
|
||||||
<td>pk</td><td>是否是Primary Key,当前仅支持int64类型</td>
|
<td>pk</td><td>是否是Primary Key,当前仅支持int64类型</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)</td><td>字段类型</td>
|
<td>当前支持30多种字段类型,详情参见 [字段类型](https://github.com/go-xorm/xorm/blob/master/docs/COLUMNTYPE.md)</td><td>字段类型</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>autoincr</td><td>是否是自增</td>
|
<td>autoincr</td><td>是否是自增</td>
|
||||||
|
|
@ -637,19 +654,19 @@ engine.ClearCache(new(User))
|
||||||
|
|
||||||
Cache implement theory below:
|
Cache implement theory below:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
<a name="130" id="130"></a>
|
<a name="130" id="130"></a>
|
||||||
## 12.xorm tool
|
## 12.xorm tool
|
||||||
xorm工具提供了xorm命令,能够帮助做很多事情。
|
xorm工具提供了xorm命令,能够帮助做很多事情。
|
||||||
|
|
||||||
### 12.1.Reverse command
|
### 12.1.Reverse command
|
||||||
Please visit [xorm tool](https://github.com/lunny/xorm/tree/master/xorm)
|
Please visit [xorm tool](https://github.com/go-xorm/xorm/tree/master/xorm)
|
||||||
|
|
||||||
<a name="140" id="140"></a>
|
<a name="140" id="140"></a>
|
||||||
## 13.Examples
|
## 13.Examples
|
||||||
|
|
||||||
请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples)
|
请访问[https://github.com/go-xorm/xorm/tree/master/examples](https://github.com/go-xorm/xorm/tree/master/examples)
|
||||||
|
|
||||||
<a name="150" id="150"></a>
|
<a name="150" id="150"></a>
|
||||||
## 14.Cases
|
## 14.Cases
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package drivers
|
package drivers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
230
engine.go
230
engine.go
|
|
@ -6,14 +6,13 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Engine is the major struct of xorm, it means a database manager.
|
// Engine is the major struct of xorm, it means a database manager.
|
||||||
|
|
@ -34,9 +33,8 @@ type Engine struct {
|
||||||
ShowWarn bool
|
ShowWarn bool
|
||||||
Pool IConnectPool
|
Pool IConnectPool
|
||||||
Filters []core.Filter
|
Filters []core.Filter
|
||||||
Logger io.Writer
|
Logger ILogger // io.Writer
|
||||||
Cacher core.Cacher
|
Cacher core.Cacher
|
||||||
tableCachers map[reflect.Type]core.Cacher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) SetMapper(mapper core.IMapper) {
|
func (engine *Engine) SetMapper(mapper core.IMapper) {
|
||||||
|
|
@ -118,9 +116,9 @@ func (engine *Engine) NoCascade() *Session {
|
||||||
|
|
||||||
// Set a table use a special cacher
|
// Set a table use a special cacher
|
||||||
func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
|
func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
|
||||||
t := rType(bean)
|
v := rValue(bean)
|
||||||
engine.autoMapType(t)
|
engine.autoMapType(v)
|
||||||
engine.tableCachers[t] = cacher
|
engine.Tables[v.Type()].Cacher = cacher
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenDB provides a interface to operate database directly.
|
// OpenDB provides a interface to operate database directly.
|
||||||
|
|
@ -144,35 +142,44 @@ func (engine *Engine) Close() error {
|
||||||
func (engine *Engine) Ping() error {
|
func (engine *Engine) Ping() error {
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
engine.LogSQL("PING DATABASE", engine.DriverName)
|
engine.LogInfo("PING DATABASE", engine.DriverName)
|
||||||
return session.Ping()
|
return session.Ping()
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging sql
|
// logging sql
|
||||||
func (engine *Engine) LogSQL(contents ...interface{}) {
|
func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
|
||||||
if engine.ShowSQL {
|
if engine.ShowSQL {
|
||||||
io.WriteString(engine.Logger, fmt.Sprintln(contents...))
|
if len(sqlArgs) > 0 {
|
||||||
|
engine.LogInfo("[sql]", sqlStr, "[args]", sqlArgs)
|
||||||
|
} else {
|
||||||
|
engine.LogInfo("[sql]", sqlStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging error
|
// logging error
|
||||||
func (engine *Engine) LogError(contents ...interface{}) {
|
func (engine *Engine) LogError(contents ...interface{}) {
|
||||||
if engine.ShowErr {
|
if engine.ShowErr {
|
||||||
io.WriteString(engine.Logger, fmt.Sprintln(contents...))
|
engine.Logger.Err(fmt.Sprintln(contents...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logging error
|
||||||
|
func (engine *Engine) LogInfo(contents ...interface{}) {
|
||||||
|
engine.Logger.Info(fmt.Sprintln(contents...))
|
||||||
|
}
|
||||||
|
|
||||||
// logging debug
|
// logging debug
|
||||||
func (engine *Engine) LogDebug(contents ...interface{}) {
|
func (engine *Engine) LogDebug(contents ...interface{}) {
|
||||||
if engine.ShowDebug {
|
if engine.ShowDebug {
|
||||||
io.WriteString(engine.Logger, fmt.Sprintln(contents...))
|
engine.Logger.Debug(fmt.Sprintln(contents...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging warn
|
// logging warn
|
||||||
func (engine *Engine) LogWarn(contents ...interface{}) {
|
func (engine *Engine) LogWarn(contents ...interface{}) {
|
||||||
if engine.ShowWarn {
|
if engine.ShowWarn {
|
||||||
io.WriteString(engine.Logger, fmt.Sprintln(contents...))
|
engine.Logger.Warning(fmt.Sprintln(contents...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,6 +307,18 @@ func (engine *Engine) Cols(columns ...string) *Session {
|
||||||
return session.Cols(columns...)
|
return session.Cols(columns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) AllCols() *Session {
|
||||||
|
session := engine.NewSession()
|
||||||
|
session.IsAutoClose = true
|
||||||
|
return session.AllCols()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) MustCols(columns ...string) *Session {
|
||||||
|
session := engine.NewSession()
|
||||||
|
session.IsAutoClose = true
|
||||||
|
return session.MustCols(columns...)
|
||||||
|
}
|
||||||
|
|
||||||
// Xorm automatically retrieve condition according struct, but
|
// Xorm automatically retrieve condition according struct, but
|
||||||
// if struct has bool field, it will ignore them. So use UseBool
|
// if struct has bool field, it will ignore them. So use UseBool
|
||||||
// to tell system to do not ignore them.
|
// to tell system to do not ignore them.
|
||||||
|
|
@ -387,12 +406,13 @@ func (engine *Engine) Having(conditions string) *Session {
|
||||||
return session.Having(conditions)
|
return session.Having(conditions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) autoMapType(t reflect.Type) *core.Table {
|
func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
|
||||||
|
t := v.Type()
|
||||||
engine.mutex.RLock()
|
engine.mutex.RLock()
|
||||||
table, ok := engine.Tables[t]
|
table, ok := engine.Tables[t]
|
||||||
engine.mutex.RUnlock()
|
engine.mutex.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
table = engine.mapType(t)
|
table = engine.mapType(v)
|
||||||
engine.mutex.Lock()
|
engine.mutex.Lock()
|
||||||
engine.Tables[t] = table
|
engine.Tables[t] = table
|
||||||
engine.mutex.Unlock()
|
engine.mutex.Unlock()
|
||||||
|
|
@ -401,26 +421,66 @@ func (engine *Engine) autoMapType(t reflect.Type) *core.Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) autoMap(bean interface{}) *core.Table {
|
func (engine *Engine) autoMap(bean interface{}) *core.Table {
|
||||||
t := rType(bean)
|
v := rValue(bean)
|
||||||
return engine.autoMapType(t)
|
return engine.autoMapType(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) mapType(t reflect.Type) *core.Table {
|
/*func (engine *Engine) mapType(t reflect.Type) *core.Table {
|
||||||
return mappingTable(t, engine.TableMapper, engine.ColumnMapper, engine.dialect, engine.TagIdentifier)
|
return mappingTable(t, engine.TableMapper, engine.ColumnMapper, engine.dialect, engine.TagIdentifier)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapper, dialect core.Dialect, tagId string) *core.Table {
|
func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapper, dialect core.Dialect, tagId string) *core.Table {
|
||||||
table := core.NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
table.Name = tableMapper.Obj2Table(t.Name())
|
table.Name = tableMapper.Obj2Table(t.Name())
|
||||||
|
*/
|
||||||
|
func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
|
||||||
|
if index, ok := table.Indexes[indexName]; ok {
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
} else {
|
||||||
|
index := core.NewIndex(indexName, indexType)
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
table.AddIndex(index)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) newTable() *core.Table {
|
||||||
|
table := core.NewEmptyTable()
|
||||||
|
table.Cacher = engine.Cacher
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) mapType(v reflect.Value) *core.Table {
|
||||||
|
t := v.Type()
|
||||||
|
table := engine.newTable()
|
||||||
|
method := v.MethodByName("TableName")
|
||||||
|
if !method.IsValid() {
|
||||||
|
method = v.Addr().MethodByName("TableName")
|
||||||
|
}
|
||||||
|
if method.IsValid() {
|
||||||
|
params := []reflect.Value{}
|
||||||
|
results := method.Call(params)
|
||||||
|
if len(results) == 1 {
|
||||||
|
table.Name = results[0].Interface().(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if table.Name == "" {
|
||||||
|
table.Name = engine.TableMapper.Obj2Table(t.Name())
|
||||||
|
}
|
||||||
table.Type = t
|
table.Type = t
|
||||||
|
|
||||||
var idFieldColName string
|
var idFieldColName string
|
||||||
|
var err error
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
tag := t.Field(i).Tag
|
tag := t.Field(i).Tag
|
||||||
ormTagStr := tag.Get(tagId)
|
ormTagStr := tag.Get(engine.TagIdentifier)
|
||||||
var col *core.Column
|
var col *core.Column
|
||||||
fieldType := t.Field(i).Type
|
fieldValue := v.Field(i)
|
||||||
|
fieldType := fieldValue.Type()
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -433,7 +493,9 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
}
|
}
|
||||||
if (strings.ToUpper(tags[0]) == "EXTENDS") &&
|
if (strings.ToUpper(tags[0]) == "EXTENDS") &&
|
||||||
(fieldType.Kind() == reflect.Struct) {
|
(fieldType.Kind() == reflect.Struct) {
|
||||||
parentTable := mappingTable(fieldType, tableMapper, colMapper, dialect, tagId)
|
|
||||||
|
//parentTable := mappingTable(fieldType, tableMapper, colMapper, dialect, tagId)
|
||||||
|
parentTable := engine.mapType(fieldValue)
|
||||||
for _, col := range parentTable.Columns() {
|
for _, col := range parentTable.Columns() {
|
||||||
col.FieldName = fmt.Sprintf("%v.%v", fieldType.Name(), col.FieldName)
|
col.FieldName = fmt.Sprintf("%v.%v", fieldType.Name(), col.FieldName)
|
||||||
table.AddColumn(col)
|
table.AddColumn(col)
|
||||||
|
|
@ -442,8 +504,9 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var indexType int
|
indexNames := make(map[string]int)
|
||||||
var indexName string
|
var isIndex, isUnique bool
|
||||||
|
var preKey string
|
||||||
for j, key := range tags {
|
for j, key := range tags {
|
||||||
k := strings.ToUpper(key)
|
k := strings.ToUpper(key)
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -456,8 +519,18 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
col.Nullable = false
|
col.Nullable = false
|
||||||
case k == "NULL":
|
case k == "NULL":
|
||||||
col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT")
|
col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT")
|
||||||
|
/*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"):
|
||||||
|
col.IsAutoIncrement = true
|
||||||
|
|
||||||
|
autoStart := k[len("AUTOINCR")+1 : len(k)-1]
|
||||||
|
autoStartInt, err := strconv.Atoi(autoStart)
|
||||||
|
if err != nil {
|
||||||
|
engine.LogError(err)
|
||||||
|
}
|
||||||
|
col.AutoIncrStart = autoStartInt*/
|
||||||
case k == "AUTOINCR":
|
case k == "AUTOINCR":
|
||||||
col.IsAutoIncrement = true
|
col.IsAutoIncrement = true
|
||||||
|
//col.AutoIncrStart = 1
|
||||||
case k == "DEFAULT":
|
case k == "DEFAULT":
|
||||||
col.Default = tags[j+1]
|
col.Default = tags[j+1]
|
||||||
case k == "CREATED":
|
case k == "CREATED":
|
||||||
|
|
@ -468,35 +541,46 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
case k == "UPDATED":
|
case k == "UPDATED":
|
||||||
col.IsUpdated = true
|
col.IsUpdated = true
|
||||||
case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
|
case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
|
||||||
indexType = core.IndexType
|
indexName := k[len("INDEX")+1 : len(k)-1]
|
||||||
indexName = k[len("INDEX")+1 : len(k)-1]
|
indexNames[indexName] = core.IndexType
|
||||||
case k == "INDEX":
|
case k == "INDEX":
|
||||||
indexType = core.IndexType
|
isIndex = true
|
||||||
case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
|
case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
|
||||||
indexName = k[len("UNIQUE")+1 : len(k)-1]
|
indexName := k[len("UNIQUE")+1 : len(k)-1]
|
||||||
indexType = core.UniqueType
|
indexNames[indexName] = core.UniqueType
|
||||||
case k == "UNIQUE":
|
case k == "UNIQUE":
|
||||||
indexType = core.UniqueType
|
isUnique = true
|
||||||
case k == "NOTNULL":
|
case k == "NOTNULL":
|
||||||
col.Nullable = false
|
col.Nullable = false
|
||||||
case k == "NOT":
|
case k == "NOT":
|
||||||
default:
|
default:
|
||||||
if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") {
|
if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") {
|
||||||
if key != col.Default {
|
if preKey != "DEFAULT" {
|
||||||
col.Name = key[1 : len(key)-1]
|
col.Name = key[1 : len(key)-1]
|
||||||
}
|
}
|
||||||
} else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") {
|
} else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") {
|
||||||
fs := strings.Split(k, "(")
|
fs := strings.Split(k, "(")
|
||||||
|
|
||||||
if _, ok := core.SqlTypes[fs[0]]; !ok {
|
if _, ok := core.SqlTypes[fs[0]]; !ok {
|
||||||
|
preKey = k
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
col.SQLType = core.SQLType{fs[0], 0, 0}
|
col.SQLType = core.SQLType{fs[0], 0, 0}
|
||||||
fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",")
|
fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",")
|
||||||
if len(fs2) == 2 {
|
if len(fs2) == 2 {
|
||||||
col.Length, _ = strconv.Atoi(fs2[0])
|
col.Length, err = strconv.Atoi(fs2[0])
|
||||||
col.Length2, _ = strconv.Atoi(fs2[1])
|
if err != nil {
|
||||||
|
engine.LogError(err)
|
||||||
|
}
|
||||||
|
col.Length2, err = strconv.Atoi(fs2[1])
|
||||||
|
if err != nil {
|
||||||
|
engine.LogError(err)
|
||||||
|
}
|
||||||
} else if len(fs2) == 1 {
|
} else if len(fs2) == 1 {
|
||||||
col.Length, _ = strconv.Atoi(fs2[0])
|
col.Length, err = strconv.Atoi(fs2[0])
|
||||||
|
if err != nil {
|
||||||
|
engine.LogError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, ok := core.SqlTypes[k]; ok {
|
if _, ok := core.SqlTypes[k]; ok {
|
||||||
|
|
@ -505,8 +589,9 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
col.Name = key
|
col.Name = key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialect.SqlType(col)
|
engine.dialect.SqlType(col)
|
||||||
}
|
}
|
||||||
|
preKey = k
|
||||||
}
|
}
|
||||||
if col.SQLType.Name == "" {
|
if col.SQLType.Name == "" {
|
||||||
col.SQLType = core.Type2SQLType(fieldType)
|
col.SQLType = core.Type2SQLType(fieldType)
|
||||||
|
|
@ -519,40 +604,24 @@ func mappingTable(t reflect.Type, tableMapper core.IMapper, colMapper core.IMapp
|
||||||
}
|
}
|
||||||
//fmt.Println("======", col)
|
//fmt.Println("======", col)
|
||||||
if col.Name == "" {
|
if col.Name == "" {
|
||||||
col.Name = colMapper.Obj2Table(t.Field(i).Name)
|
col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
|
||||||
}
|
}
|
||||||
if indexType == core.IndexType {
|
|
||||||
if indexName == "" {
|
if isUnique {
|
||||||
indexName = col.Name
|
indexNames[col.Name] = core.UniqueType
|
||||||
}
|
} else if isIndex {
|
||||||
if index, ok := table.Indexes[indexName]; ok {
|
indexNames[col.Name] = core.IndexType
|
||||||
index.AddColumn(col.Name)
|
|
||||||
col.Indexes[index.Name] = true
|
|
||||||
} else {
|
|
||||||
index := core.NewIndex(indexName, core.IndexType)
|
|
||||||
index.AddColumn(col.Name)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Indexes[index.Name] = true
|
|
||||||
}
|
|
||||||
} else if indexType == core.UniqueType {
|
|
||||||
if indexName == "" {
|
|
||||||
indexName = col.Name
|
|
||||||
}
|
|
||||||
if index, ok := table.Indexes[indexName]; ok {
|
|
||||||
index.AddColumn(col.Name)
|
|
||||||
col.Indexes[index.Name] = true
|
|
||||||
} else {
|
|
||||||
index := core.NewIndex(indexName, core.UniqueType)
|
|
||||||
index.AddColumn(col.Name)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Indexes[index.Name] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for indexName, indexType := range indexNames {
|
||||||
|
addIndex(indexName, table, col, indexType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sqlType := core.Type2SQLType(fieldType)
|
sqlType := core.Type2SQLType(fieldType)
|
||||||
col = core.NewColumn(colMapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
|
col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name),
|
||||||
sqlType.DefaultLength, sqlType.DefaultLength2, true)
|
t.Field(i).Name, sqlType, sqlType.DefaultLength,
|
||||||
|
sqlType.DefaultLength2, true)
|
||||||
}
|
}
|
||||||
if col.IsAutoIncrement {
|
if col.IsAutoIncrement {
|
||||||
col.Nullable = false
|
col.Nullable = false
|
||||||
|
|
@ -582,19 +651,20 @@ func (engine *Engine) mapping(beans ...interface{}) (e error) {
|
||||||
engine.mutex.Lock()
|
engine.mutex.Lock()
|
||||||
defer engine.mutex.Unlock()
|
defer engine.mutex.Unlock()
|
||||||
for _, bean := range beans {
|
for _, bean := range beans {
|
||||||
t := rType(bean)
|
v := rValue(bean)
|
||||||
engine.Tables[t] = engine.mapType(t)
|
engine.Tables[v.Type()] = engine.mapType(v)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a table has any reocrd
|
// If a table has any reocrd
|
||||||
func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
|
func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
|
||||||
t := rType(bean)
|
v := rValue(bean)
|
||||||
|
t := v.Type()
|
||||||
if t.Kind() != reflect.Struct {
|
if t.Kind() != reflect.Struct {
|
||||||
return false, errors.New("bean should be a struct or struct's point")
|
return false, errors.New("bean should be a struct or struct's point")
|
||||||
}
|
}
|
||||||
engine.autoMapType(t)
|
engine.autoMapType(v)
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
rows, err := session.Count(bean)
|
rows, err := session.Count(bean)
|
||||||
|
|
@ -603,11 +673,11 @@ func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
|
||||||
|
|
||||||
// If a table is exist
|
// If a table is exist
|
||||||
func (engine *Engine) IsTableExist(bean interface{}) (bool, error) {
|
func (engine *Engine) IsTableExist(bean interface{}) (bool, error) {
|
||||||
t := rType(bean)
|
v := rValue(bean)
|
||||||
if t.Kind() != reflect.Struct {
|
if v.Type().Kind() != reflect.Struct {
|
||||||
return false, errors.New("bean should be a struct or struct's point")
|
return false, errors.New("bean should be a struct or struct's point")
|
||||||
}
|
}
|
||||||
table := engine.autoMapType(t)
|
table := engine.autoMapType(v)
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
has, err := session.isTableExist(table.Name)
|
has, err := session.isTableExist(table.Name)
|
||||||
|
|
@ -646,9 +716,13 @@ func (engine *Engine) CreateUniques(bean interface{}) error {
|
||||||
return session.CreateUniques(bean)
|
return session.CreateUniques(bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) getCacher(t reflect.Type) core.Cacher {
|
func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
|
||||||
if cacher, ok := engine.tableCachers[t]; ok {
|
return table.Cacher
|
||||||
return cacher
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) getCacher(v reflect.Value) core.Cacher {
|
||||||
|
if table := engine.autoMapType(v); table != nil {
|
||||||
|
return table.Cacher
|
||||||
}
|
}
|
||||||
return engine.Cacher
|
return engine.Cacher
|
||||||
}
|
}
|
||||||
|
|
@ -660,7 +734,10 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
|
||||||
return errors.New("error params")
|
return errors.New("error params")
|
||||||
}
|
}
|
||||||
table := engine.autoMap(bean)
|
table := engine.autoMap(bean)
|
||||||
cacher := engine.getCacher(t)
|
cacher := table.Cacher
|
||||||
|
if cacher == nil {
|
||||||
|
cacher = engine.Cacher
|
||||||
|
}
|
||||||
if cacher != nil {
|
if cacher != nil {
|
||||||
cacher.ClearIds(table.Name)
|
cacher.ClearIds(table.Name)
|
||||||
cacher.DelBean(table.Name, id)
|
cacher.DelBean(table.Name, id)
|
||||||
|
|
@ -676,7 +753,10 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
|
||||||
return errors.New("error params")
|
return errors.New("error params")
|
||||||
}
|
}
|
||||||
table := engine.autoMap(bean)
|
table := engine.autoMap(bean)
|
||||||
cacher := engine.getCacher(t)
|
cacher := table.Cacher
|
||||||
|
if cacher == nil {
|
||||||
|
cacher = engine.Cacher
|
||||||
|
}
|
||||||
if cacher != nil {
|
if cacher != nil {
|
||||||
cacher.ClearIds(table.Name)
|
cacher.ClearIds(table.Name)
|
||||||
cacher.ClearBeans(table.Name)
|
cacher.ClearBeans(table.Name)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/lunny/xorm/caches"
|
"github.com/go-xorm/xorm/caches"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/bylevel/pq"
|
_ "github.com/bylevel/pq"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/lunny/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func indexNoCase(s, sep string) int {
|
func indexNoCase(s, sep string) int {
|
||||||
|
|
@ -38,9 +38,14 @@ func makeArray(elem string, count int) []string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rValue(bean interface{}) reflect.Value {
|
||||||
|
return reflect.Indirect(reflect.ValueOf(bean))
|
||||||
|
}
|
||||||
|
|
||||||
func rType(bean interface{}) reflect.Type {
|
func rType(bean interface{}) reflect.Type {
|
||||||
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
|
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
|
||||||
return reflect.TypeOf(sliceValue.Interface())
|
//return reflect.TypeOf(sliceValue.Interface())
|
||||||
|
return sliceValue.Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
func structName(v reflect.Type) string {
|
func structName(v reflect.Type) string {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package xorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// logger interface, log/syslog conform with this interface
|
||||||
|
type ILogger interface {
|
||||||
|
Debug(m string) (err error)
|
||||||
|
Err(m string) (err error)
|
||||||
|
Info(m string) (err error)
|
||||||
|
Warning(m string) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleLogger struct {
|
||||||
|
logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimpleLogger(out io.Writer) *SimpleLogger {
|
||||||
|
return &SimpleLogger{
|
||||||
|
logger: log.New(out, "[xorm] ", log.Ldate|log.Lmicroseconds)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
|
||||||
|
return &SimpleLogger{
|
||||||
|
logger: log.New(out, prefix, flag)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleLogger) Debug(m string) (err error) {
|
||||||
|
s.logger.Println("[debug]", m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleLogger) Err(m string) (err error) {
|
||||||
|
s.logger.Println("[error]", m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleLogger) Info(m string) (err error) {
|
||||||
|
s.logger.Println("[info]", m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleLogger) Warning(m string) (err error) {
|
||||||
|
s.logger.Println("[warning]", m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -1,67 +1,63 @@
|
||||||
package dialects
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"crypto/tls"
|
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
//"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
//"time"
|
|
||||||
|
|
||||||
. "github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// func init() {
|
||||||
RegisterDialect("mssql", &mssql{})
|
// RegisterDialect("mssql", &mssql{})
|
||||||
}
|
// }
|
||||||
|
|
||||||
type mssql struct {
|
type mssql struct {
|
||||||
Base
|
core.Base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) Init(uri *Uri, drivername, dataSourceName string) error {
|
func (db *mssql) Init(uri *core.Uri, drivername, dataSourceName string) error {
|
||||||
return db.Base.Init(db, uri, drivername, dataSourceName)
|
return db.Base.Init(db, uri, drivername, dataSourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) SqlType(c *Column) string {
|
func (db *mssql) SqlType(c *core.Column) string {
|
||||||
var res string
|
var res string
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case Bool:
|
case core.Bool:
|
||||||
res = TinyInt
|
res = core.TinyInt
|
||||||
case Serial:
|
case core.Serial:
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.IsPrimaryKey = true
|
c.IsPrimaryKey = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
res = Int
|
res = core.Int
|
||||||
case BigSerial:
|
case core.BigSerial:
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.IsPrimaryKey = true
|
c.IsPrimaryKey = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
res = BigInt
|
res = core.BigInt
|
||||||
case Bytea, Blob, Binary, TinyBlob, MediumBlob, LongBlob:
|
case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
||||||
res = VarBinary
|
res = core.VarBinary
|
||||||
if c.Length == 0 {
|
if c.Length == 0 {
|
||||||
c.Length = 50
|
c.Length = 50
|
||||||
}
|
}
|
||||||
case TimeStamp:
|
case core.TimeStamp:
|
||||||
res = DateTime
|
res = core.DateTime
|
||||||
case TimeStampz:
|
case core.TimeStampz:
|
||||||
res = "DATETIMEOFFSET"
|
res = "DATETIMEOFFSET"
|
||||||
c.Length = 7
|
c.Length = 7
|
||||||
case MediumInt:
|
case core.MediumInt:
|
||||||
res = Int
|
res = core.Int
|
||||||
case MediumText, TinyText, LongText:
|
case core.MediumText, core.TinyText, core.LongText:
|
||||||
res = Text
|
res = core.Text
|
||||||
case Double:
|
case core.Double:
|
||||||
res = Real
|
res = core.Real
|
||||||
default:
|
default:
|
||||||
res = t
|
res = t
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == Int {
|
if res == core.Int {
|
||||||
return Int
|
return core.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasLen1 bool = (c.Length > 0)
|
var hasLen1 bool = (c.Length > 0)
|
||||||
|
|
@ -90,6 +86,12 @@ func (db *mssql) AutoIncrStr() string {
|
||||||
return "IDENTITY"
|
return "IDENTITY"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *mssql) DropTableSql(tableName string) string {
|
||||||
|
return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
|
||||||
|
"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
|
||||||
|
"DROP TABLE \"%s\"", tableName, tableName)
|
||||||
|
}
|
||||||
|
|
||||||
func (db *mssql) SupportCharset() bool {
|
func (db *mssql) SupportCharset() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -116,12 +118,12 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
return sql, args
|
return sql, args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
|
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
|
||||||
from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
|
from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
|
||||||
where a.object_id=object_id('` + tableName + `')`
|
where a.object_id=object_id('` + tableName + `')`
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +133,7 @@ where a.object_id=object_id('` + tableName + `')`
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
cols := make(map[string]*Column)
|
cols := make(map[string]*core.Column)
|
||||||
colSeq := make([]string, 0)
|
colSeq := make([]string, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var name, ctype, precision, scale string
|
var name, ctype, precision, scale string
|
||||||
|
|
@ -141,7 +143,7 @@ where a.object_id=object_id('` + tableName + `')`
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
col := new(Column)
|
col := new(core.Column)
|
||||||
col.Indexes = make(map[string]bool)
|
col.Indexes = make(map[string]bool)
|
||||||
col.Length = maxLen
|
col.Length = maxLen
|
||||||
col.Name = strings.Trim(name, "` ")
|
col.Name = strings.Trim(name, "` ")
|
||||||
|
|
@ -149,14 +151,14 @@ where a.object_id=object_id('` + tableName + `')`
|
||||||
ct := strings.ToUpper(ctype)
|
ct := strings.ToUpper(ctype)
|
||||||
switch ct {
|
switch ct {
|
||||||
case "DATETIMEOFFSET":
|
case "DATETIMEOFFSET":
|
||||||
col.SQLType = SQLType{TimeStampz, 0, 0}
|
col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
|
||||||
case "NVARCHAR":
|
case "NVARCHAR":
|
||||||
col.SQLType = SQLType{Varchar, 0, 0}
|
col.SQLType = core.SQLType{core.Varchar, 0, 0}
|
||||||
case "IMAGE":
|
case "IMAGE":
|
||||||
col.SQLType = SQLType{VarBinary, 0, 0}
|
col.SQLType = core.SQLType{core.VarBinary, 0, 0}
|
||||||
default:
|
default:
|
||||||
if _, ok := SqlTypes[ct]; ok {
|
if _, ok := core.SqlTypes[ct]; ok {
|
||||||
col.SQLType = SQLType{ct, 0, 0}
|
col.SQLType = core.SQLType{ct, 0, 0}
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, errors.New(fmt.Sprintf("unknow colType %v for %v - %v",
|
return nil, nil, errors.New(fmt.Sprintf("unknow colType %v for %v - %v",
|
||||||
ct, tableName, col.Name))
|
ct, tableName, col.Name))
|
||||||
|
|
@ -166,6 +168,10 @@ where a.object_id=object_id('` + tableName + `')`
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
if col.Default != "" {
|
if col.Default != "" {
|
||||||
col.Default = "'" + col.Default + "'"
|
col.Default = "'" + col.Default + "'"
|
||||||
|
} else {
|
||||||
|
if col.DefaultIsEmpty {
|
||||||
|
col.Default = "''"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cols[col.Name] = col
|
cols[col.Name] = col
|
||||||
|
|
@ -174,10 +180,10 @@ where a.object_id=object_id('` + tableName + `')`
|
||||||
return colSeq, cols, nil
|
return colSeq, cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) GetTables() ([]*Table, error) {
|
func (db *mssql) GetTables() ([]*core.Table, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := `select name from sysobjects where xtype ='U'`
|
s := `select name from sysobjects where xtype ='U'`
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -187,9 +193,9 @@ func (db *mssql) GetTables() ([]*Table, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tables := make([]*Table, 0)
|
tables := make([]*core.Table, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
table := NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
var name string
|
var name string
|
||||||
err = rows.Scan(&name)
|
err = rows.Scan(&name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -201,7 +207,7 @@ func (db *mssql) GetTables() ([]*Table, error) {
|
||||||
return tables, nil
|
return tables, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) GetIndexes(tableName string) (map[string]*Index, error) {
|
func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := `SELECT
|
s := `SELECT
|
||||||
IXS.NAME AS [INDEX_NAME],
|
IXS.NAME AS [INDEX_NAME],
|
||||||
|
|
@ -217,7 +223,7 @@ INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID
|
||||||
AND IXCS.COLUMN_ID=C.COLUMN_ID
|
AND IXCS.COLUMN_ID=C.COLUMN_ID
|
||||||
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||||
`
|
`
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +233,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexes := make(map[string]*Index, 0)
|
indexes := make(map[string]*core.Index, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var indexType int
|
var indexType int
|
||||||
var indexName, colName, isUnique string
|
var indexName, colName, isUnique string
|
||||||
|
|
@ -243,9 +249,9 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||||
}
|
}
|
||||||
|
|
||||||
if i {
|
if i {
|
||||||
indexType = UniqueType
|
indexType = core.UniqueType
|
||||||
} else {
|
} else {
|
||||||
indexType = IndexType
|
indexType = core.IndexType
|
||||||
}
|
}
|
||||||
|
|
||||||
colName = strings.Trim(colName, "` ")
|
colName = strings.Trim(colName, "` ")
|
||||||
|
|
@ -254,10 +260,10 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||||
indexName = indexName[5+len(tableName) : len(indexName)]
|
indexName = indexName[5+len(tableName) : len(indexName)]
|
||||||
}
|
}
|
||||||
|
|
||||||
var index *Index
|
var index *core.Index
|
||||||
var ok bool
|
var ok bool
|
||||||
if index, ok = indexes[indexName]; !ok {
|
if index, ok = indexes[indexName]; !ok {
|
||||||
index = new(Index)
|
index = new(core.Index)
|
||||||
index.Type = indexType
|
index.Type = indexType
|
||||||
index.Name = indexName
|
index.Name = indexName
|
||||||
indexes[indexName] = index
|
indexes[indexName] = index
|
||||||
|
|
@ -267,7 +273,7 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
|
||||||
return indexes, nil
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) CreateTablSql(table *Table, tableName, storeEngine, charset string) string {
|
func (db *mssql) CreateTablSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||||
var sql string
|
var sql string
|
||||||
if tableName == "" {
|
if tableName == "" {
|
||||||
tableName = table.Name
|
tableName = table.Name
|
||||||
|
|
@ -301,6 +307,6 @@ func (db *mssql) CreateTablSql(table *Table, tableName, storeEngine, charset str
|
||||||
return sql
|
return sql
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mssql) Filters() []Filter {
|
func (db *mssql) Filters() []core.Filter {
|
||||||
return []Filter{&IdFilter{}, &QuoteFilter{}}
|
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dialects
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
|
@ -8,15 +8,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// func init() {
|
||||||
RegisterDialect("mysql", &mysql{})
|
// RegisterDialect("mysql", &mysql{})
|
||||||
}
|
// }
|
||||||
|
|
||||||
type mysql struct {
|
type mysql struct {
|
||||||
Base
|
core.Base
|
||||||
net string
|
net string
|
||||||
addr string
|
addr string
|
||||||
params map[string]string
|
params map[string]string
|
||||||
|
|
@ -28,29 +28,30 @@ type mysql struct {
|
||||||
clientFoundRows bool
|
clientFoundRows bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) Init(uri *Uri, drivername, dataSourceName string) error {
|
func (db *mysql) Init(uri *core.Uri, drivername, dataSourceName string) error {
|
||||||
return db.Base.Init(db, uri, drivername, dataSourceName)
|
return db.Base.Init(db, uri, drivername, dataSourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) SqlType(c *Column) string {
|
func (db *mysql) SqlType(c *core.Column) string {
|
||||||
var res string
|
var res string
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case Bool:
|
case core.Bool:
|
||||||
res = TinyInt
|
res = core.TinyInt
|
||||||
case Serial:
|
c.Length = 1
|
||||||
|
case core.Serial:
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.IsPrimaryKey = true
|
c.IsPrimaryKey = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
res = Int
|
res = core.Int
|
||||||
case BigSerial:
|
case core.BigSerial:
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.IsPrimaryKey = true
|
c.IsPrimaryKey = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
res = BigInt
|
res = core.BigInt
|
||||||
case Bytea:
|
case core.Bytea:
|
||||||
res = Blob
|
res = core.Blob
|
||||||
case TimeStampz:
|
case core.TimeStampz:
|
||||||
res = Char
|
res = core.Char
|
||||||
c.Length = 64
|
c.Length = 64
|
||||||
default:
|
default:
|
||||||
res = t
|
res = t
|
||||||
|
|
@ -109,23 +110,26 @@ func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
return sql, args
|
return sql, args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{db.DbName, tableName}
|
args := []interface{}{db.DbName, tableName}
|
||||||
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
|
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` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
defer cnn.Close()
|
defer cnn.Close()
|
||||||
|
|
||||||
rows, err := cnn.Query(s, args...)
|
rows, err := cnn.Query(s, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
cols := make(map[string]*Column)
|
defer rows.Close()
|
||||||
|
|
||||||
|
cols := make(map[string]*core.Column)
|
||||||
colSeq := make([]string, 0)
|
colSeq := make([]string, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
col := new(Column)
|
col := new(core.Column)
|
||||||
col.Indexes = make(map[string]bool)
|
col.Indexes = make(map[string]bool)
|
||||||
|
|
||||||
var columnName, isNullable, colType, colKey, extra string
|
var columnName, isNullable, colType, colKey, extra string
|
||||||
|
|
@ -163,8 +167,8 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err
|
||||||
colType = strings.ToUpper(colName)
|
colType = strings.ToUpper(colName)
|
||||||
col.Length = len1
|
col.Length = len1
|
||||||
col.Length2 = len2
|
col.Length2 = len2
|
||||||
if _, ok := SqlTypes[colType]; ok {
|
if _, ok := core.SqlTypes[colType]; ok {
|
||||||
col.SQLType = SQLType{colType, len1, len2}
|
col.SQLType = core.SQLType{colType, len1, len2}
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
|
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
|
||||||
}
|
}
|
||||||
|
|
@ -191,10 +195,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err
|
||||||
return colSeq, cols, nil
|
return colSeq, cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) GetTables() ([]*Table, error) {
|
func (db *mysql) GetTables() ([]*core.Table, error) {
|
||||||
args := []interface{}{db.DbName}
|
args := []interface{}{db.DbName}
|
||||||
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=?"
|
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=?"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -204,9 +208,9 @@ func (db *mysql) GetTables() ([]*Table, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tables := make([]*Table, 0)
|
tables := make([]*core.Table, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
table := NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
var name, engine, tableRows string
|
var name, engine, tableRows string
|
||||||
var autoIncr *string
|
var autoIncr *string
|
||||||
err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
|
err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
|
||||||
|
|
@ -220,10 +224,10 @@ func (db *mysql) GetTables() ([]*Table, error) {
|
||||||
return tables, nil
|
return tables, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||||
args := []interface{}{db.DbName, tableName}
|
args := []interface{}{db.DbName, tableName}
|
||||||
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -233,7 +237,7 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexes := make(map[string]*Index, 0)
|
indexes := make(map[string]*core.Index, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var indexType int
|
var indexType int
|
||||||
var indexName, colName, nonUnique string
|
var indexName, colName, nonUnique string
|
||||||
|
|
@ -247,9 +251,9 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if "YES" == nonUnique || nonUnique == "1" {
|
if "YES" == nonUnique || nonUnique == "1" {
|
||||||
indexType = IndexType
|
indexType = core.IndexType
|
||||||
} else {
|
} else {
|
||||||
indexType = UniqueType
|
indexType = core.UniqueType
|
||||||
}
|
}
|
||||||
|
|
||||||
colName = strings.Trim(colName, "` ")
|
colName = strings.Trim(colName, "` ")
|
||||||
|
|
@ -258,10 +262,10 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
indexName = indexName[5+len(tableName) : len(indexName)]
|
indexName = indexName[5+len(tableName) : len(indexName)]
|
||||||
}
|
}
|
||||||
|
|
||||||
var index *Index
|
var index *core.Index
|
||||||
var ok bool
|
var ok bool
|
||||||
if index, ok = indexes[indexName]; !ok {
|
if index, ok = indexes[indexName]; !ok {
|
||||||
index = new(Index)
|
index = new(core.Index)
|
||||||
index.Type = indexType
|
index.Type = indexType
|
||||||
index.Name = indexName
|
index.Name = indexName
|
||||||
indexes[indexName] = index
|
indexes[indexName] = index
|
||||||
|
|
@ -271,6 +275,6 @@ func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
return indexes, nil
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) Filters() []Filter {
|
func (db *mysql) Filters() []core.Filter {
|
||||||
return []Filter{&IdFilter{}}
|
return []core.Filter{&core.IdFilter{}}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dialects
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -6,37 +6,37 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// func init() {
|
||||||
RegisterDialect("oracle", &oracle{})
|
// RegisterDialect("oracle", &oracle{})
|
||||||
}
|
// }
|
||||||
|
|
||||||
type oracle struct {
|
type oracle struct {
|
||||||
Base
|
core.Base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) Init(uri *Uri, drivername, dataSourceName string) error {
|
func (db *oracle) Init(uri *core.Uri, drivername, dataSourceName string) error {
|
||||||
return db.Base.Init(db, uri, drivername, dataSourceName)
|
return db.Base.Init(db, uri, drivername, dataSourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) SqlType(c *Column) string {
|
func (db *oracle) SqlType(c *core.Column) string {
|
||||||
var res string
|
var res string
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool, Serial, BigSerial:
|
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
|
||||||
return "NUMBER"
|
return "NUMBER"
|
||||||
case Binary, VarBinary, Blob, TinyBlob, MediumBlob, LongBlob, Bytea:
|
case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
|
||||||
return Blob
|
return core.Blob
|
||||||
case Time, DateTime, TimeStamp:
|
case core.Time, core.DateTime, core.TimeStamp:
|
||||||
res = TimeStamp
|
res = core.TimeStamp
|
||||||
case TimeStampz:
|
case core.TimeStampz:
|
||||||
res = "TIMESTAMP WITH TIME ZONE"
|
res = "TIMESTAMP WITH TIME ZONE"
|
||||||
case Float, Double, Numeric, Decimal:
|
case core.Float, core.Double, core.Numeric, core.Decimal:
|
||||||
res = "NUMBER"
|
res = "NUMBER"
|
||||||
case Text, MediumText, LongText:
|
case core.Text, core.MediumText, core.LongText:
|
||||||
res = "CLOB"
|
res = "CLOB"
|
||||||
case Char, Varchar, TinyText:
|
case core.Char, core.Varchar, core.TinyText:
|
||||||
return "VARCHAR2"
|
return "VARCHAR2"
|
||||||
default:
|
default:
|
||||||
res = t
|
res = t
|
||||||
|
|
@ -93,12 +93,12 @@ func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface
|
||||||
" AND column_name = ?", args
|
" AND column_name = ?", args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{strings.ToUpper(tableName)}
|
args := []interface{}{strings.ToUpper(tableName)}
|
||||||
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
|
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
|
||||||
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
|
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
|
||||||
|
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -109,10 +109,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
cols := make(map[string]*Column)
|
cols := make(map[string]*core.Column)
|
||||||
colSeq := make([]string, 0)
|
colSeq := make([]string, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
col := new(Column)
|
col := new(core.Column)
|
||||||
col.Indexes = make(map[string]bool)
|
col.Indexes = make(map[string]bool)
|
||||||
|
|
||||||
var colName, colDefault, nullable, dataType, dataPrecision, dataScale string
|
var colName, colDefault, nullable, dataType, dataPrecision, dataScale string
|
||||||
|
|
@ -135,13 +135,13 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er
|
||||||
|
|
||||||
switch dataType {
|
switch dataType {
|
||||||
case "VARCHAR2":
|
case "VARCHAR2":
|
||||||
col.SQLType = SQLType{Varchar, 0, 0}
|
col.SQLType = core.SQLType{core.Varchar, 0, 0}
|
||||||
case "TIMESTAMP WITH TIME ZONE":
|
case "TIMESTAMP WITH TIME ZONE":
|
||||||
col.SQLType = SQLType{TimeStampz, 0, 0}
|
col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
|
||||||
default:
|
default:
|
||||||
col.SQLType = SQLType{strings.ToUpper(dataType), 0, 0}
|
col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0}
|
||||||
}
|
}
|
||||||
if _, ok := SqlTypes[col.SQLType.Name]; !ok {
|
if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
|
||||||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
|
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,6 +150,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
if col.Default != "" {
|
if col.Default != "" {
|
||||||
col.Default = "'" + col.Default + "'"
|
col.Default = "'" + col.Default + "'"
|
||||||
|
} else {
|
||||||
|
if col.DefaultIsEmpty {
|
||||||
|
col.Default = "''"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cols[col.Name] = col
|
cols[col.Name] = col
|
||||||
|
|
@ -159,10 +163,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er
|
||||||
return colSeq, cols, nil
|
return colSeq, cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) GetTables() ([]*Table, error) {
|
func (db *oracle) GetTables() ([]*core.Table, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := "SELECT table_name FROM user_tables"
|
s := "SELECT table_name FROM user_tables"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -172,9 +176,9 @@ func (db *oracle) GetTables() ([]*Table, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tables := make([]*Table, 0)
|
tables := make([]*core.Table, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
table := NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
err = rows.Scan(&table.Name)
|
err = rows.Scan(&table.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -185,12 +189,12 @@ func (db *oracle) GetTables() ([]*Table, error) {
|
||||||
return tables, nil
|
return tables, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
|
s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
|
||||||
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
|
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
|
||||||
|
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +205,7 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
indexes := make(map[string]*Index, 0)
|
indexes := make(map[string]*core.Index, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var indexType int
|
var indexType int
|
||||||
var indexName, colName, uniqueness string
|
var indexName, colName, uniqueness string
|
||||||
|
|
@ -214,15 +218,15 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
indexName = strings.Trim(indexName, `" `)
|
indexName = strings.Trim(indexName, `" `)
|
||||||
|
|
||||||
if uniqueness == "UNIQUE" {
|
if uniqueness == "UNIQUE" {
|
||||||
indexType = UniqueType
|
indexType = core.UniqueType
|
||||||
} else {
|
} else {
|
||||||
indexType = IndexType
|
indexType = core.IndexType
|
||||||
}
|
}
|
||||||
|
|
||||||
var index *Index
|
var index *core.Index
|
||||||
var ok bool
|
var ok bool
|
||||||
if index, ok = indexes[indexName]; !ok {
|
if index, ok = indexes[indexName]; !ok {
|
||||||
index = new(Index)
|
index = new(core.Index)
|
||||||
index.Type = indexType
|
index.Type = indexType
|
||||||
index.Name = indexName
|
index.Name = indexName
|
||||||
indexes[indexName] = index
|
indexes[indexName] = index
|
||||||
|
|
@ -236,7 +240,7 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
type OracleSeqFilter struct {
|
type OracleSeqFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OracleSeqFilter) Do(sql string, dialect Dialect, table *Table) string {
|
func (s *OracleSeqFilter) Do(sql string, dialect core.Dialect, table *core.Table) string {
|
||||||
counts := strings.Count(sql, "?")
|
counts := strings.Count(sql, "?")
|
||||||
for i := 1; i <= counts; i++ {
|
for i := 1; i <= counts; i++ {
|
||||||
newstr := ":" + fmt.Sprintf("%v", i)
|
newstr := ":" + fmt.Sprintf("%v", i)
|
||||||
|
|
@ -245,6 +249,6 @@ func (s *OracleSeqFilter) Do(sql string, dialect Dialect, table *Table) string {
|
||||||
return sql
|
return sql
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *oracle) Filters() []Filter {
|
func (db *oracle) Filters() []core.Filter {
|
||||||
return []Filter{&QuoteFilter{}, &OracleSeqFilter{}, &IdFilter{}}
|
return []core.Filter{&core.QuoteFilter{}, &OracleSeqFilter{}, &core.IdFilter{}}
|
||||||
}
|
}
|
||||||
7
pool.go
7
pool.go
|
|
@ -1,13 +1,12 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
//"fmt"
|
|
||||||
"sync"
|
|
||||||
//"sync/atomic"
|
|
||||||
"container/list"
|
"container/list"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface IConnecPool is a connection pool interface, all implements should implement
|
// Interface IConnecPool is a connection pool interface, all implements should implement
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dialects
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -6,53 +6,53 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// func init() {
|
||||||
RegisterDialect("postgres", &postgres{})
|
// RegisterDialect("postgres", &postgres{})
|
||||||
}
|
// }
|
||||||
|
|
||||||
type postgres struct {
|
type postgres struct {
|
||||||
Base
|
core.Base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) Init(uri *Uri, drivername, dataSourceName string) error {
|
func (db *postgres) Init(uri *core.Uri, drivername, dataSourceName string) error {
|
||||||
return db.Base.Init(db, uri, drivername, dataSourceName)
|
return db.Base.Init(db, uri, drivername, dataSourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) SqlType(c *Column) string {
|
func (db *postgres) SqlType(c *core.Column) string {
|
||||||
var res string
|
var res string
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case TinyInt:
|
case core.TinyInt:
|
||||||
res = SmallInt
|
res = core.SmallInt
|
||||||
return res
|
return res
|
||||||
case MediumInt, Int, Integer:
|
case core.MediumInt, core.Int, core.Integer:
|
||||||
if c.IsAutoIncrement {
|
if c.IsAutoIncrement {
|
||||||
return Serial
|
return core.Serial
|
||||||
}
|
}
|
||||||
return Integer
|
return core.Integer
|
||||||
case Serial, BigSerial:
|
case core.Serial, core.BigSerial:
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
res = t
|
res = t
|
||||||
case Binary, VarBinary:
|
case core.Binary, core.VarBinary:
|
||||||
return Bytea
|
return core.Bytea
|
||||||
case DateTime:
|
case core.DateTime:
|
||||||
res = TimeStamp
|
res = core.TimeStamp
|
||||||
case TimeStampz:
|
case core.TimeStampz:
|
||||||
return "timestamp with time zone"
|
return "timestamp with time zone"
|
||||||
case Float:
|
case core.Float:
|
||||||
res = Real
|
res = core.Real
|
||||||
case TinyText, MediumText, LongText:
|
case core.TinyText, core.MediumText, core.LongText:
|
||||||
res = Text
|
res = core.Text
|
||||||
case Blob, TinyBlob, MediumBlob, LongBlob:
|
case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
|
||||||
return Bytea
|
return core.Bytea
|
||||||
case Double:
|
case core.Double:
|
||||||
return "DOUBLE PRECISION"
|
return "DOUBLE PRECISION"
|
||||||
default:
|
default:
|
||||||
if c.IsAutoIncrement {
|
if c.IsAutoIncrement {
|
||||||
return Serial
|
return core.Serial
|
||||||
}
|
}
|
||||||
res = t
|
res = t
|
||||||
}
|
}
|
||||||
|
|
@ -108,11 +108,11 @@ func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interfa
|
||||||
" AND column_name = ?", args
|
" AND column_name = ?", args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := "SELECT column_name, column_default, is_nullable, data_type, character_maximum_length" +
|
s := "SELECT column_name, column_default, is_nullable, data_type, character_maximum_length" +
|
||||||
", numeric_precision, numeric_precision_radix FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1"
|
", numeric_precision, numeric_precision_radix FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -121,12 +121,13 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
cols := make(map[string]*Column)
|
cols := make(map[string]*core.Column)
|
||||||
colSeq := make([]string, 0)
|
colSeq := make([]string, 0)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
col := new(Column)
|
col := new(core.Column)
|
||||||
col.Indexes = make(map[string]bool)
|
col.Indexes = make(map[string]bool)
|
||||||
|
|
||||||
var colName, isNullable, dataType string
|
var colName, isNullable, dataType string
|
||||||
var maxLenStr, colDefault, numPrecision, numRadix *string
|
var maxLenStr, colDefault, numPrecision, numRadix *string
|
||||||
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix)
|
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix)
|
||||||
|
|
@ -160,21 +161,21 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column,
|
||||||
|
|
||||||
switch dataType {
|
switch dataType {
|
||||||
case "character varying", "character":
|
case "character varying", "character":
|
||||||
col.SQLType = SQLType{Varchar, 0, 0}
|
col.SQLType = core.SQLType{core.Varchar, 0, 0}
|
||||||
case "timestamp without time zone":
|
case "timestamp without time zone":
|
||||||
col.SQLType = SQLType{DateTime, 0, 0}
|
col.SQLType = core.SQLType{core.DateTime, 0, 0}
|
||||||
case "timestamp with time zone":
|
case "timestamp with time zone":
|
||||||
col.SQLType = SQLType{TimeStampz, 0, 0}
|
col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
|
||||||
case "double precision":
|
case "double precision":
|
||||||
col.SQLType = SQLType{Double, 0, 0}
|
col.SQLType = core.SQLType{core.Double, 0, 0}
|
||||||
case "boolean":
|
case "boolean":
|
||||||
col.SQLType = SQLType{Bool, 0, 0}
|
col.SQLType = core.SQLType{core.Bool, 0, 0}
|
||||||
case "time without time zone":
|
case "time without time zone":
|
||||||
col.SQLType = SQLType{Time, 0, 0}
|
col.SQLType = core.SQLType{core.Time, 0, 0}
|
||||||
default:
|
default:
|
||||||
col.SQLType = SQLType{strings.ToUpper(dataType), 0, 0}
|
col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0}
|
||||||
}
|
}
|
||||||
if _, ok := SqlTypes[col.SQLType.Name]; !ok {
|
if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
|
||||||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
|
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,6 +184,10 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column,
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
if col.Default != "" {
|
if col.Default != "" {
|
||||||
col.Default = "'" + col.Default + "'"
|
col.Default = "'" + col.Default + "'"
|
||||||
|
} else {
|
||||||
|
if col.DefaultIsEmpty {
|
||||||
|
col.Default = "''"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cols[col.Name] = col
|
cols[col.Name] = col
|
||||||
|
|
@ -192,10 +197,10 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column,
|
||||||
return colSeq, cols, nil
|
return colSeq, cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) GetTables() ([]*Table, error) {
|
func (db *postgres) GetTables() ([]*core.Table, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
|
s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -205,9 +210,9 @@ func (db *postgres) GetTables() ([]*Table, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tables := make([]*Table, 0)
|
tables := make([]*core.Table, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
table := NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
var name string
|
var name string
|
||||||
err = rows.Scan(&name)
|
err = rows.Scan(&name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -219,11 +224,11 @@ func (db *postgres) GetTables() ([]*Table, error) {
|
||||||
return tables, nil
|
return tables, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' and tablename = $1"
|
s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' and tablename = $1"
|
||||||
|
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -233,7 +238,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexes := make(map[string]*Index, 0)
|
indexes := make(map[string]*core.Index, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var indexType int
|
var indexType int
|
||||||
var indexName, indexdef string
|
var indexName, indexdef string
|
||||||
|
|
@ -245,9 +250,9 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
indexName = strings.Trim(indexName, `" `)
|
indexName = strings.Trim(indexName, `" `)
|
||||||
|
|
||||||
if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
|
if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
|
||||||
indexType = UniqueType
|
indexType = core.UniqueType
|
||||||
} else {
|
} else {
|
||||||
indexType = IndexType
|
indexType = core.IndexType
|
||||||
}
|
}
|
||||||
cs := strings.Split(indexdef, "(")
|
cs := strings.Split(indexdef, "(")
|
||||||
colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
|
colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
|
||||||
|
|
@ -262,7 +267,7 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index := &Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
|
index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
|
||||||
for _, colName := range colNames {
|
for _, colName := range colNames {
|
||||||
index.Cols = append(index.Cols, strings.Trim(colName, `" `))
|
index.Cols = append(index.Cols, strings.Trim(colName, `" `))
|
||||||
}
|
}
|
||||||
|
|
@ -271,23 +276,6 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
return indexes, nil
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PgSeqFilter filter SQL replace ?, ? ... to $1, $2 ...
|
func (db *postgres) Filters() []core.Filter {
|
||||||
type PgSeqFilter struct {
|
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{"$", 1}}
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PgSeqFilter) Do(sql string, dialect Dialect, table *Table) string {
|
|
||||||
segs := strings.Split(sql, "?")
|
|
||||||
size := len(segs)
|
|
||||||
res := ""
|
|
||||||
for i, c := range segs {
|
|
||||||
if i < size-1 {
|
|
||||||
res += c + fmt.Sprintf("$%v", i+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res += segs[size-1]
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *postgres) Filters() []Filter {
|
|
||||||
return []Filter{&IdFilter{}, &QuoteFilter{}, &PgSeqFilter{}}
|
|
||||||
}
|
}
|
||||||
15
rows.go
15
rows.go
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Rows struct {
|
type Rows struct {
|
||||||
|
|
@ -32,24 +32,23 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
|
||||||
|
|
||||||
defer rows.session.Statement.Init()
|
defer rows.session.Statement.Init()
|
||||||
|
|
||||||
var sql string
|
var sqlStr string
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
rows.session.Statement.RefTable = rows.session.Engine.autoMap(bean)
|
rows.session.Statement.RefTable = rows.session.Engine.autoMap(bean)
|
||||||
if rows.session.Statement.RawSQL == "" {
|
if rows.session.Statement.RawSQL == "" {
|
||||||
sql, args = rows.session.Statement.genGetSql(bean)
|
sqlStr, args = rows.session.Statement.genGetSql(bean)
|
||||||
} else {
|
} else {
|
||||||
sql = rows.session.Statement.RawSQL
|
sqlStr = rows.session.Statement.RawSQL
|
||||||
args = rows.session.Statement.RawParams
|
args = rows.session.Statement.RawParams
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range rows.session.Engine.Filters {
|
for _, filter := range rows.session.Engine.Filters {
|
||||||
sql = filter.Do(sql, session.Engine.dialect, rows.session.Statement.RefTable)
|
sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.session.Engine.LogSQL(sql)
|
rows.session.Engine.logSQL(sqlStr, args)
|
||||||
rows.session.Engine.LogSQL(args)
|
|
||||||
|
|
||||||
rows.stmt, err = rows.session.Db.Prepare(sql)
|
rows.stmt, err = rows.session.Db.Prepare(sqlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rows.lastError = err
|
rows.lastError = err
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
|
||||||
104
session.go
104
session.go
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Struct Session keep a pointer to sql.DB and provides all execution of all
|
// Struct Session keep a pointer to sql.DB and provides all execution of all
|
||||||
|
|
@ -134,6 +134,16 @@ func (session *Session) Cols(columns ...string) *Session {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *Session) AllCols() *Session {
|
||||||
|
session.Statement.AllCols()
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *Session) MustCols(columns ...string) *Session {
|
||||||
|
session.Statement.MustCols(columns...)
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
func (session *Session) NoCascade() *Session {
|
func (session *Session) NoCascade() *Session {
|
||||||
session.Statement.UseCascade = false
|
session.Statement.UseCascade = false
|
||||||
return session
|
return session
|
||||||
|
|
@ -282,7 +292,7 @@ func (session *Session) Begin() error {
|
||||||
session.IsCommitedOrRollbacked = false
|
session.IsCommitedOrRollbacked = false
|
||||||
session.Tx = tx
|
session.Tx = tx
|
||||||
|
|
||||||
session.Engine.LogSQL("BEGIN TRANSACTION")
|
session.Engine.logSQL("BEGIN TRANSACTION")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -290,7 +300,7 @@ func (session *Session) Begin() error {
|
||||||
// When using transaction, you can rollback if any error
|
// When using transaction, you can rollback if any error
|
||||||
func (session *Session) Rollback() error {
|
func (session *Session) Rollback() error {
|
||||||
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
|
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
|
||||||
session.Engine.LogSQL("ROLL BACK")
|
session.Engine.logSQL(session.Engine.dialect.RollBackStr())
|
||||||
session.IsCommitedOrRollbacked = true
|
session.IsCommitedOrRollbacked = true
|
||||||
return session.Tx.Rollback()
|
return session.Tx.Rollback()
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +310,7 @@ func (session *Session) Rollback() error {
|
||||||
// When using transaction, Commit will commit all operations.
|
// When using transaction, Commit will commit all operations.
|
||||||
func (session *Session) Commit() error {
|
func (session *Session) Commit() error {
|
||||||
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
|
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
|
||||||
session.Engine.LogSQL("COMMIT")
|
session.Engine.logSQL("COMMIT")
|
||||||
session.IsCommitedOrRollbacked = true
|
session.IsCommitedOrRollbacked = true
|
||||||
var err error
|
var err error
|
||||||
if err = session.Tx.Commit(); err == nil {
|
if err = session.Tx.Commit(); err == nil {
|
||||||
|
|
@ -357,13 +367,14 @@ func cleanupProcessorsClosures(slices *[]func(interface{})) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error {
|
func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error {
|
||||||
dataStruct := reflect.Indirect(reflect.ValueOf(obj))
|
dataStruct := rValue(obj)
|
||||||
if dataStruct.Kind() != reflect.Struct {
|
if dataStruct.Kind() != reflect.Struct {
|
||||||
return errors.New("Expected a pointer to a struct")
|
return errors.New("Expected a pointer to a struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
table := session.Engine.autoMapType(rType(obj))
|
|
||||||
var col *core.Column
|
var col *core.Column
|
||||||
|
table := session.Engine.autoMapType(dataStruct)
|
||||||
|
|
||||||
for key, data := range objMap {
|
for key, data := range objMap {
|
||||||
if col = table.GetColumn(key); col == nil {
|
if col = table.GetColumn(key); col == nil {
|
||||||
session.Engine.LogWarn(fmt.Sprintf("table %v's has not column %v. %v", table.Name, key, table.Columns()))
|
session.Engine.LogWarn(fmt.Sprintf("table %v's has not column %v. %v", table.Name, key, table.Columns()))
|
||||||
|
|
@ -419,8 +430,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
|
||||||
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
|
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.Engine.LogSQL(sqlStr)
|
session.Engine.logSQL(sqlStr, args)
|
||||||
session.Engine.LogSQL(args)
|
|
||||||
|
|
||||||
if session.IsAutoCommit {
|
if session.IsAutoCommit {
|
||||||
return session.innerExec(sqlStr, args...)
|
return session.innerExec(sqlStr, args...)
|
||||||
|
|
@ -610,7 +620,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
|
||||||
return false, ErrCacheFailed
|
return false, ErrCacheFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
cacher := session.Engine.getCacher(session.Statement.RefTable.Type)
|
cacher := session.Engine.getCacher2(session.Statement.RefTable)
|
||||||
tableName := session.Statement.TableName()
|
tableName := session.Statement.TableName()
|
||||||
session.Engine.LogDebug("[xorm:cacheGet] find sql:", newsql, args)
|
session.Engine.LogDebug("[xorm:cacheGet] find sql:", newsql, args)
|
||||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
||||||
|
|
@ -699,7 +709,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
|
||||||
}
|
}
|
||||||
|
|
||||||
table := session.Statement.RefTable
|
table := session.Statement.RefTable
|
||||||
cacher := session.Engine.getCacher(t)
|
cacher := session.Engine.getCacher2(table)
|
||||||
ids, err := core.GetCacheSql(cacher, session.Statement.TableName(), newsql, args)
|
ids, err := core.GetCacheSql(cacher, session.Statement.TableName(), newsql, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//session.Engine.LogError(err)
|
//session.Engine.LogError(err)
|
||||||
|
|
@ -928,6 +938,7 @@ func (session *Session) Get(bean interface{}) (bool, error) {
|
||||||
session.Statement.Limit(1)
|
session.Statement.Limit(1)
|
||||||
var sqlStr string
|
var sqlStr string
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
|
|
||||||
session.Statement.RefTable = session.Engine.autoMap(bean)
|
session.Statement.RefTable = session.Engine.autoMap(bean)
|
||||||
|
|
||||||
if session.Statement.RawSQL == "" {
|
if session.Statement.RawSQL == "" {
|
||||||
|
|
@ -937,7 +948,7 @@ func (session *Session) Get(bean interface{}) (bool, error) {
|
||||||
args = session.Statement.RawParams
|
args = session.Statement.RawParams
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(session.Statement.RefTable.Type); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
|
||||||
has, err := session.cacheGet(bean, sqlStr, args...)
|
has, err := session.cacheGet(bean, sqlStr, args...)
|
||||||
if err != ErrCacheFailed {
|
if err != ErrCacheFailed {
|
||||||
return has, err
|
return has, err
|
||||||
|
|
@ -1052,12 +1063,14 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
if session.Statement.RefTable == nil {
|
if session.Statement.RefTable == nil {
|
||||||
if sliceElementType.Kind() == reflect.Ptr {
|
if sliceElementType.Kind() == reflect.Ptr {
|
||||||
if sliceElementType.Elem().Kind() == reflect.Struct {
|
if sliceElementType.Elem().Kind() == reflect.Struct {
|
||||||
table = session.Engine.autoMapType(sliceElementType.Elem())
|
pv := reflect.New(sliceElementType.Elem())
|
||||||
|
table = session.Engine.autoMapType(pv.Elem())
|
||||||
} else {
|
} else {
|
||||||
return errors.New("slice type")
|
return errors.New("slice type")
|
||||||
}
|
}
|
||||||
} else if sliceElementType.Kind() == reflect.Struct {
|
} else if sliceElementType.Kind() == reflect.Struct {
|
||||||
table = session.Engine.autoMapType(sliceElementType)
|
pv := reflect.New(sliceElementType)
|
||||||
|
table = session.Engine.autoMapType(pv.Elem())
|
||||||
} else {
|
} else {
|
||||||
return errors.New("slice type")
|
return errors.New("slice type")
|
||||||
}
|
}
|
||||||
|
|
@ -1068,7 +1081,8 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
|
|
||||||
if len(condiBean) > 0 {
|
if len(condiBean) > 0 {
|
||||||
colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
|
colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
|
||||||
false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
|
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
|
||||||
|
session.Statement.mustColumnMap)
|
||||||
session.Statement.ConditionStr = strings.Join(colNames, " AND ")
|
session.Statement.ConditionStr = strings.Join(colNames, " AND ")
|
||||||
session.Statement.BeanArgs = args
|
session.Statement.BeanArgs = args
|
||||||
}
|
}
|
||||||
|
|
@ -1090,7 +1104,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
args = session.Statement.RawParams
|
args = session.Statement.RawParams
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(table.Type); cacher != nil &&
|
if cacher := session.Engine.getCacher2(table); cacher != nil &&
|
||||||
session.Statement.UseCache &&
|
session.Statement.UseCache &&
|
||||||
!session.Statement.IsDistinct {
|
!session.Statement.IsDistinct {
|
||||||
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
|
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
|
||||||
|
|
@ -1427,13 +1441,12 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
|
func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
|
||||||
|
dataStruct := rValue(bean)
|
||||||
dataStruct := reflect.Indirect(reflect.ValueOf(bean))
|
|
||||||
if dataStruct.Kind() != reflect.Struct {
|
if dataStruct.Kind() != reflect.Struct {
|
||||||
return errors.New("Expected a pointer to a struct")
|
return errors.New("Expected a pointer to a struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
table := session.Engine.autoMapType(rType(bean))
|
table := session.Engine.autoMapType(dataStruct)
|
||||||
|
|
||||||
scanResultContainers := make([]interface{}, len(fields))
|
scanResultContainers := make([]interface{}, len(fields))
|
||||||
for i := 0; i < len(fields); i++ {
|
for i := 0; i < len(fields); i++ {
|
||||||
|
|
@ -1480,7 +1493,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
|
||||||
x := reflect.New(fieldType)
|
x := reflect.New(fieldType)
|
||||||
err := json.Unmarshal([]byte(vv.String()), x.Interface())
|
err := json.Unmarshal([]byte(vv.String()), x.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.Engine.LogSQL(err)
|
session.Engine.LogError(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fieldValue.Set(x.Elem())
|
fieldValue.Set(x.Elem())
|
||||||
|
|
@ -1534,7 +1547,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
|
||||||
fieldValue.Set(vv)
|
fieldValue.Set(vv)
|
||||||
}
|
}
|
||||||
} else if session.Statement.UseCascade {
|
} else if session.Statement.UseCascade {
|
||||||
table := session.Engine.autoMapType(fieldValue.Type())
|
table := session.Engine.autoMapType(*fieldValue)
|
||||||
if table != nil {
|
if table != nil {
|
||||||
var x int64
|
var x int64
|
||||||
if rawValueType.Kind() == reflect.Int64 {
|
if rawValueType.Kind() == reflect.Int64 {
|
||||||
|
|
@ -1700,8 +1713,7 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{})
|
||||||
*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
|
*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.Engine.LogSQL(*sqlStr)
|
session.Engine.logSQL(*sqlStr, paramStr)
|
||||||
session.Engine.LogSQL(paramStr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||||
|
|
@ -1803,9 +1815,10 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
}
|
}
|
||||||
|
|
||||||
bean := sliceValue.Index(0).Interface()
|
bean := sliceValue.Index(0).Interface()
|
||||||
sliceElementType := rType(bean)
|
elementValue := rValue(bean)
|
||||||
|
//sliceElementType := elementValue.Type()
|
||||||
|
|
||||||
table := session.Engine.autoMapType(sliceElementType)
|
table := session.Engine.autoMapType(elementValue)
|
||||||
session.Statement.RefTable = table
|
session.Statement.RefTable = table
|
||||||
|
|
||||||
size := sliceValue.Len()
|
size := sliceValue.Len()
|
||||||
|
|
@ -1903,7 +1916,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(table.Type); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
|
||||||
session.cacheInsert(session.Statement.TableName())
|
session.cacheInsert(session.Statement.TableName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2113,7 +2126,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
|
||||||
v = x
|
v = x
|
||||||
fieldValue.Set(reflect.ValueOf(v))
|
fieldValue.Set(reflect.ValueOf(v))
|
||||||
} else if session.Statement.UseCascade {
|
} else if session.Statement.UseCascade {
|
||||||
table := session.Engine.autoMapType(fieldValue.Type())
|
table := session.Engine.autoMapType(*fieldValue)
|
||||||
if table != nil {
|
if table != nil {
|
||||||
x, err := strconv.ParseInt(string(data), 10, 64)
|
x, err := strconv.ParseInt(string(data), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -2467,7 +2480,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
|
||||||
case reflect.Complex64, reflect.Complex128:
|
case reflect.Complex64, reflect.Complex128:
|
||||||
bytes, err := json.Marshal(fieldValue.Interface())
|
bytes, err := json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.Engine.LogSQL(err)
|
session.Engine.LogError(err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
|
|
@ -2479,7 +2492,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
bytes, err := json.Marshal(fieldValue.Interface())
|
bytes, err := json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.Engine.LogSQL(err)
|
session.Engine.LogError(err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
|
|
@ -2492,7 +2505,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
|
||||||
} else {
|
} else {
|
||||||
bytes, err = json.Marshal(fieldValue.Interface())
|
bytes, err = json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.Engine.LogSQL(err)
|
session.Engine.LogError(err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2526,6 +2539,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
colPlaces := strings.Repeat("?, ", len(colNames))
|
colPlaces := strings.Repeat("?, ", len(colNames))
|
||||||
|
//fmt.Println(colNames, args)
|
||||||
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
||||||
|
|
||||||
sqlStr := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)",
|
sqlStr := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)",
|
||||||
|
|
@ -2577,7 +2591,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
handleAfterInsertProcessorFunc(bean)
|
handleAfterInsertProcessorFunc(bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(table.Type); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
|
||||||
session.cacheInsert(session.Statement.TableName())
|
session.cacheInsert(session.Statement.TableName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2636,7 +2650,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
handleAfterInsertProcessorFunc(bean)
|
handleAfterInsertProcessorFunc(bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(table.Type); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
|
||||||
session.cacheInsert(session.Statement.TableName())
|
session.cacheInsert(session.Statement.TableName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2689,7 +2703,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
|
|
||||||
// Method InsertOne insert only one struct into database as a record.
|
// Method InsertOne insert only one struct into database as a record.
|
||||||
// The in parameter bean must a struct or a point to struct. The return
|
// The in parameter bean must a struct or a point to struct. The return
|
||||||
// parameter is lastInsertId and error
|
// parameter is inserted and error
|
||||||
func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
||||||
err := session.newDb()
|
err := session.newDb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -2749,7 +2763,7 @@ func (session *Session) cacheInsert(tables ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
table := session.Statement.RefTable
|
table := session.Statement.RefTable
|
||||||
cacher := session.Engine.getCacher(table.Type)
|
cacher := session.Engine.getCacher2(table)
|
||||||
|
|
||||||
for _, t := range tables {
|
for _, t := range tables {
|
||||||
session.Engine.LogDebug("cache clear:", t)
|
session.Engine.LogDebug("cache clear:", t)
|
||||||
|
|
@ -2783,7 +2797,7 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table := session.Statement.RefTable
|
table := session.Statement.RefTable
|
||||||
cacher := session.Engine.getCacher(table.Type)
|
cacher := session.Engine.getCacher2(table)
|
||||||
tableName := session.Statement.TableName()
|
tableName := session.Statement.TableName()
|
||||||
session.Engine.LogDebug("[xorm:cacheUpdate] get cache sql", newsql, args[nStart:])
|
session.Engine.LogDebug("[xorm:cacheUpdate] get cache sql", newsql, args[nStart:])
|
||||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
|
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
|
||||||
|
|
@ -2908,7 +2922,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
|
|
||||||
if session.Statement.ColumnStr == "" {
|
if session.Statement.ColumnStr == "" {
|
||||||
colNames, args = buildConditions(session.Engine, table, bean, false, false,
|
colNames, args = buildConditions(session.Engine, table, bean, false, false,
|
||||||
false, false, session.Statement.allUseBool, session.Statement.boolColumnMap)
|
false, false, session.Statement.allUseBool, session.Statement.useAllCols,
|
||||||
|
session.Statement.mustColumnMap)
|
||||||
} else {
|
} else {
|
||||||
colNames, args, err = genCols(table, session, bean, true, true)
|
colNames, args, err = genCols(table, session, bean, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -2942,7 +2957,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
|
|
||||||
if len(condiBean) > 0 {
|
if len(condiBean) > 0 {
|
||||||
condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true,
|
condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true,
|
||||||
false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
|
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
|
||||||
|
session.Statement.mustColumnMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
var condition = ""
|
var condition = ""
|
||||||
|
|
@ -2965,6 +2981,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
|
|
||||||
var sqlStr, inSql string
|
var sqlStr, inSql string
|
||||||
var inArgs []interface{}
|
var inArgs []interface{}
|
||||||
|
doIncVer := false
|
||||||
|
var verValue *reflect.Value
|
||||||
if table.Version != "" && session.Statement.checkVersion {
|
if table.Version != "" && session.Statement.checkVersion {
|
||||||
if condition != "" {
|
if condition != "" {
|
||||||
condition = fmt.Sprintf("WHERE (%v) AND %v = ?", condition,
|
condition = fmt.Sprintf("WHERE (%v) AND %v = ?", condition,
|
||||||
|
|
@ -2987,12 +3005,13 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1",
|
session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1",
|
||||||
condition)
|
condition)
|
||||||
|
|
||||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
verValue, err = table.VersionColumn().ValueOf(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
condiArgs = append(condiArgs, verValue.Interface())
|
condiArgs = append(condiArgs, verValue.Interface())
|
||||||
|
doIncVer = true
|
||||||
} else {
|
} else {
|
||||||
if condition != "" {
|
if condition != "" {
|
||||||
condition = "WHERE " + condition
|
condition = "WHERE " + condition
|
||||||
|
|
@ -3019,9 +3038,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
res, err := session.exec(sqlStr, args...)
|
res, err := session.exec(sqlStr, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
} else if doIncVer {
|
||||||
|
verValue.SetInt(verValue.Int() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(t); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
|
||||||
//session.cacheUpdate(sqlStr, args...)
|
//session.cacheUpdate(sqlStr, args...)
|
||||||
cacher.ClearIds(session.Statement.TableName())
|
cacher.ClearIds(session.Statement.TableName())
|
||||||
cacher.ClearBeans(session.Statement.TableName())
|
cacher.ClearBeans(session.Statement.TableName())
|
||||||
|
|
@ -3073,7 +3094,7 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
|
||||||
return ErrCacheFailed
|
return ErrCacheFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
cacher := session.Engine.getCacher(session.Statement.RefTable.Type)
|
cacher := session.Engine.getCacher2(session.Statement.RefTable)
|
||||||
tableName := session.Statement.TableName()
|
tableName := session.Statement.TableName()
|
||||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -3139,7 +3160,8 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
|
||||||
table := session.Engine.autoMap(bean)
|
table := session.Engine.autoMap(bean)
|
||||||
session.Statement.RefTable = table
|
session.Statement.RefTable = table
|
||||||
colNames, args := buildConditions(session.Engine, table, bean, true, true,
|
colNames, args := buildConditions(session.Engine, table, bean, true, true,
|
||||||
false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
|
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
|
||||||
|
session.Statement.mustColumnMap)
|
||||||
|
|
||||||
var condition = ""
|
var condition = ""
|
||||||
|
|
||||||
|
|
@ -3169,7 +3191,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
|
||||||
|
|
||||||
args = append(session.Statement.Params, args...)
|
args = append(session.Statement.Params, args...)
|
||||||
|
|
||||||
if cacher := session.Engine.getCacher(session.Statement.RefTable.Type); cacher != nil && session.Statement.UseCache {
|
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
|
||||||
session.cacheDelete(sqlStr, args...)
|
session.cacheDelete(sqlStr, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,44 @@
|
||||||
package dialects
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// func init() {
|
||||||
RegisterDialect("sqlite3", &sqlite3{})
|
// RegisterDialect("sqlite3", &sqlite3{})
|
||||||
}
|
// }
|
||||||
|
|
||||||
type sqlite3 struct {
|
type sqlite3 struct {
|
||||||
Base
|
core.Base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) Init(uri *Uri, drivername, dataSourceName string) error {
|
func (db *sqlite3) Init(uri *core.Uri, drivername, dataSourceName string) error {
|
||||||
return db.Base.Init(db, uri, drivername, dataSourceName)
|
return db.Base.Init(db, uri, drivername, dataSourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) SqlType(c *Column) string {
|
func (db *sqlite3) SqlType(c *core.Column) string {
|
||||||
switch t := c.SQLType.Name; t {
|
switch t := c.SQLType.Name; t {
|
||||||
case Date, DateTime, TimeStamp, Time:
|
case core.Date, core.DateTime, core.TimeStamp, core.Time:
|
||||||
return Numeric
|
return core.Numeric
|
||||||
case TimeStampz:
|
case core.TimeStampz:
|
||||||
return Text
|
return core.Text
|
||||||
case Char, Varchar, TinyText, Text, MediumText, LongText:
|
case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText:
|
||||||
return Text
|
return core.Text
|
||||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool:
|
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool:
|
||||||
return Integer
|
return core.Integer
|
||||||
case Float, Double, Real:
|
case core.Float, core.Double, core.Real:
|
||||||
return Real
|
return core.Real
|
||||||
case Decimal, Numeric:
|
case core.Decimal, core.Numeric:
|
||||||
return Numeric
|
return core.Numeric
|
||||||
case TinyBlob, Blob, MediumBlob, LongBlob, Bytea, Binary, VarBinary:
|
case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
|
||||||
return Blob
|
return core.Blob
|
||||||
case Serial, BigSerial:
|
case core.Serial, core.BigSerial:
|
||||||
c.IsPrimaryKey = true
|
c.IsPrimaryKey = true
|
||||||
c.IsAutoIncrement = true
|
c.IsAutoIncrement = true
|
||||||
c.Nullable = false
|
c.Nullable = false
|
||||||
return Integer
|
return core.Integer
|
||||||
default:
|
default:
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
@ -84,10 +84,10 @@ func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interfac
|
||||||
return sql, args
|
return sql, args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -110,11 +110,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e
|
||||||
nStart := strings.Index(name, "(")
|
nStart := strings.Index(name, "(")
|
||||||
nEnd := strings.Index(name, ")")
|
nEnd := strings.Index(name, ")")
|
||||||
colCreates := strings.Split(name[nStart+1:nEnd], ",")
|
colCreates := strings.Split(name[nStart+1:nEnd], ",")
|
||||||
cols := make(map[string]*Column)
|
cols := make(map[string]*core.Column)
|
||||||
colSeq := make([]string, 0)
|
colSeq := make([]string, 0)
|
||||||
for _, colStr := range colCreates {
|
for _, colStr := range colCreates {
|
||||||
fields := strings.Fields(strings.TrimSpace(colStr))
|
fields := strings.Fields(strings.TrimSpace(colStr))
|
||||||
col := new(Column)
|
col := new(core.Column)
|
||||||
col.Indexes = make(map[string]bool)
|
col.Indexes = make(map[string]bool)
|
||||||
col.Nullable = true
|
col.Nullable = true
|
||||||
for idx, field := range fields {
|
for idx, field := range fields {
|
||||||
|
|
@ -122,7 +122,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e
|
||||||
col.Name = strings.Trim(field, "`[] ")
|
col.Name = strings.Trim(field, "`[] ")
|
||||||
continue
|
continue
|
||||||
} else if idx == 1 {
|
} else if idx == 1 {
|
||||||
col.SQLType = SQLType{field, 0, 0}
|
col.SQLType = core.SQLType{field, 0, 0}
|
||||||
}
|
}
|
||||||
switch field {
|
switch field {
|
||||||
case "PRIMARY":
|
case "PRIMARY":
|
||||||
|
|
@ -143,11 +143,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*Column, e
|
||||||
return colSeq, cols, nil
|
return colSeq, cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) GetTables() ([]*Table, error) {
|
func (db *sqlite3) GetTables() ([]*core.Table, error) {
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
||||||
|
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -158,9 +158,9 @@ func (db *sqlite3) GetTables() ([]*Table, error) {
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
tables := make([]*Table, 0)
|
tables := make([]*core.Table, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
table := NewEmptyTable()
|
table := core.NewEmptyTable()
|
||||||
err = rows.Scan(&table.Name)
|
err = rows.Scan(&table.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -173,10 +173,10 @@ func (db *sqlite3) GetTables() ([]*Table, error) {
|
||||||
return tables, nil
|
return tables, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
||||||
cnn, err := Open(db.DriverName(), db.DataSourceName())
|
cnn, err := core.Open(db.DriverName(), db.DataSourceName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +187,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
indexes := make(map[string]*Index, 0)
|
indexes := make(map[string]*core.Index, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var sql string
|
var sql string
|
||||||
err = rows.Scan(&sql)
|
err = rows.Scan(&sql)
|
||||||
|
|
@ -199,7 +199,7 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
index := new(Index)
|
index := new(core.Index)
|
||||||
nNStart := strings.Index(sql, "INDEX")
|
nNStart := strings.Index(sql, "INDEX")
|
||||||
nNEnd := strings.Index(sql, "ON")
|
nNEnd := strings.Index(sql, "ON")
|
||||||
if nNStart == -1 || nNEnd == -1 {
|
if nNStart == -1 || nNEnd == -1 {
|
||||||
|
|
@ -215,9 +215,9 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
||||||
index.Type = UniqueType
|
index.Type = core.UniqueType
|
||||||
} else {
|
} else {
|
||||||
index.Type = IndexType
|
index.Type = core.IndexType
|
||||||
}
|
}
|
||||||
|
|
||||||
nStart := strings.Index(sql, "(")
|
nStart := strings.Index(sql, "(")
|
||||||
|
|
@ -234,6 +234,6 @@ func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
return indexes, nil
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) Filters() []Filter {
|
func (db *sqlite3) Filters() []core.Filter {
|
||||||
return []Filter{&IdFilter{}}
|
return []core.Filter{&core.IdFilter{}}
|
||||||
}
|
}
|
||||||
86
statement.go
86
statement.go
|
|
@ -1,15 +1,13 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"bytes"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
//"strconv"
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type inParam struct {
|
type inParam struct {
|
||||||
|
|
@ -32,6 +30,7 @@ type Statement struct {
|
||||||
HavingStr string
|
HavingStr string
|
||||||
ColumnStr string
|
ColumnStr string
|
||||||
columnMap map[string]bool
|
columnMap map[string]bool
|
||||||
|
useAllCols bool
|
||||||
OmitStr string
|
OmitStr string
|
||||||
ConditionStr string
|
ConditionStr string
|
||||||
AltTableName string
|
AltTableName string
|
||||||
|
|
@ -47,7 +46,7 @@ type Statement struct {
|
||||||
IsDistinct bool
|
IsDistinct bool
|
||||||
allUseBool bool
|
allUseBool bool
|
||||||
checkVersion bool
|
checkVersion bool
|
||||||
boolColumnMap map[string]bool
|
mustColumnMap map[string]bool
|
||||||
inColumns map[string]*inParam
|
inColumns map[string]*inParam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,6 +67,7 @@ func (statement *Statement) Init() {
|
||||||
statement.columnMap = make(map[string]bool)
|
statement.columnMap = make(map[string]bool)
|
||||||
statement.ConditionStr = ""
|
statement.ConditionStr = ""
|
||||||
statement.AltTableName = ""
|
statement.AltTableName = ""
|
||||||
|
statement.IdParam = nil
|
||||||
statement.RawSQL = ""
|
statement.RawSQL = ""
|
||||||
statement.RawParams = make([]interface{}, 0)
|
statement.RawParams = make([]interface{}, 0)
|
||||||
statement.BeanArgs = make([]interface{}, 0)
|
statement.BeanArgs = make([]interface{}, 0)
|
||||||
|
|
@ -75,7 +75,7 @@ func (statement *Statement) Init() {
|
||||||
statement.UseAutoTime = true
|
statement.UseAutoTime = true
|
||||||
statement.IsDistinct = false
|
statement.IsDistinct = false
|
||||||
statement.allUseBool = false
|
statement.allUseBool = false
|
||||||
statement.boolColumnMap = make(map[string]bool)
|
statement.mustColumnMap = make(map[string]bool)
|
||||||
statement.checkVersion = true
|
statement.checkVersion = true
|
||||||
statement.inColumns = make(map[string]*inParam)
|
statement.inColumns = make(map[string]*inParam)
|
||||||
}
|
}
|
||||||
|
|
@ -118,11 +118,12 @@ func (statement *Statement) Or(querystring string, args ...interface{}) *Stateme
|
||||||
|
|
||||||
// tempororily set table name
|
// tempororily set table name
|
||||||
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
t := rType(tableNameOrBean)
|
v := rValue(tableNameOrBean)
|
||||||
|
t := v.Type()
|
||||||
if t.Kind() == reflect.String {
|
if t.Kind() == reflect.String {
|
||||||
statement.AltTableName = tableNameOrBean.(string)
|
statement.AltTableName = tableNameOrBean.(string)
|
||||||
} else if t.Kind() == reflect.Struct {
|
} else if t.Kind() == reflect.Struct {
|
||||||
statement.RefTable = statement.Engine.autoMapType(t)
|
statement.RefTable = statement.Engine.autoMapType(v)
|
||||||
}
|
}
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +211,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
bytes, err := json.Marshal(fieldValue.Interface())
|
bytes, err := json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
engine.LogSQL(err)
|
engine.LogError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = string(bytes)
|
val = string(bytes)
|
||||||
|
|
@ -227,7 +228,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
} else {
|
} else {
|
||||||
bytes, err = json.Marshal(fieldValue.Interface())
|
bytes, err = json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
engine.LogSQL(err)
|
engine.LogError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = bytes
|
val = bytes
|
||||||
|
|
@ -245,8 +246,9 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
|
|
||||||
// Auto generating conditions according a struct
|
// Auto generating conditions according a struct
|
||||||
func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, allUseBool bool,
|
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||||
boolColumnMap map[string]bool) ([]string, []interface{}) {
|
includeAutoIncr bool, allUseBool bool, useAllCols bool,
|
||||||
|
mustColumnMap map[string]bool) ([]string, []interface{}) {
|
||||||
|
|
||||||
colNames := make([]string, 0)
|
colNames := make([]string, 0)
|
||||||
var args = make([]interface{}, 0)
|
var args = make([]interface{}, 0)
|
||||||
|
|
@ -274,7 +276,15 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
fieldValue := *fieldValuePtr
|
fieldValue := *fieldValuePtr
|
||||||
fieldType := reflect.TypeOf(fieldValue.Interface())
|
fieldType := reflect.TypeOf(fieldValue.Interface())
|
||||||
|
|
||||||
requiredField := false
|
requiredField := useAllCols
|
||||||
|
if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
|
||||||
|
if b {
|
||||||
|
requiredField = true
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if fieldType.Kind() == reflect.Ptr {
|
if fieldType.Kind() == reflect.Ptr {
|
||||||
if fieldValue.IsNil() {
|
if fieldValue.IsNil() {
|
||||||
if includeNil {
|
if includeNil {
|
||||||
|
|
@ -297,8 +307,6 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
if allUseBool || requiredField {
|
if allUseBool || requiredField {
|
||||||
val = fieldValue.Interface()
|
val = fieldValue.Interface()
|
||||||
} else if _, ok := boolColumnMap[col.Name]; ok {
|
|
||||||
val = fieldValue.Interface()
|
|
||||||
} else {
|
} else {
|
||||||
// if a bool in a struct, it will not be as a condition because it default is false,
|
// if a bool in a struct, it will not be as a condition because it default is false,
|
||||||
// please use Where() instead
|
// please use Where() instead
|
||||||
|
|
@ -346,7 +354,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
val = t
|
val = t
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
engine.autoMapType(fieldValue.Type())
|
engine.autoMapType(fieldValue)
|
||||||
if table, ok := engine.Tables[fieldValue.Type()]; ok {
|
if table, ok := engine.Tables[fieldValue.Type()]; ok {
|
||||||
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)
|
||||||
|
|
@ -373,7 +381,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
if col.SQLType.IsText() {
|
if col.SQLType.IsText() {
|
||||||
bytes, err := json.Marshal(fieldValue.Interface())
|
bytes, err := json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
engine.LogSQL(err)
|
engine.LogError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = string(bytes)
|
val = string(bytes)
|
||||||
|
|
@ -390,7 +398,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
|
||||||
} else {
|
} else {
|
||||||
bytes, err = json.Marshal(fieldValue.Interface())
|
bytes, err = json.Marshal(fieldValue.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
engine.LogSQL(err)
|
engine.LogError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = bytes
|
val = bytes
|
||||||
|
|
@ -534,13 +542,34 @@ func (statement *Statement) Cols(columns ...string) *Statement {
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update use only: update all columns
|
||||||
|
func (statement *Statement) AllCols() *Statement {
|
||||||
|
statement.useAllCols = true
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update use only: must update columns
|
||||||
|
func (statement *Statement) MustCols(columns ...string) *Statement {
|
||||||
|
newColumns := col2NewCols(columns...)
|
||||||
|
for _, nc := range newColumns {
|
||||||
|
statement.mustColumnMap[strings.ToLower(nc)] = true
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update use only: not update columns
|
||||||
|
/*func (statement *Statement) NotCols(columns ...string) *Statement {
|
||||||
|
newColumns := col2NewCols(columns...)
|
||||||
|
for _, nc := range newColumns {
|
||||||
|
statement.mustColumnMap[strings.ToLower(nc)] = false
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}*/
|
||||||
|
|
||||||
// indicates that use bool fields as update contents and query contiditions
|
// indicates that use bool fields as update contents and query contiditions
|
||||||
func (statement *Statement) UseBool(columns ...string) *Statement {
|
func (statement *Statement) UseBool(columns ...string) *Statement {
|
||||||
if len(columns) > 0 {
|
if len(columns) > 0 {
|
||||||
newColumns := col2NewCols(columns...)
|
statement.MustCols(columns...)
|
||||||
for _, nc := range newColumns {
|
|
||||||
statement.boolColumnMap[strings.ToLower(nc)] = true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
statement.allUseBool = true
|
statement.allUseBool = true
|
||||||
}
|
}
|
||||||
|
|
@ -676,13 +705,7 @@ func (s *Statement) genDelIndexSQL() []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Statement) genDropSQL() string {
|
func (s *Statement) genDropSQL() string {
|
||||||
if s.Engine.dialect.DBType() == core.MSSQL {
|
return s.Engine.dialect.DropTableSql(s.TableName()) + ";"
|
||||||
return "IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'" +
|
|
||||||
s.TableName() + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1) " +
|
|
||||||
"DROP TABLE " + s.Engine.Quote(s.TableName()) + ";"
|
|
||||||
} else {
|
|
||||||
return "DROP TABLE IF EXISTS " + s.Engine.Quote(s.TableName()) + ";"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
|
func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
|
||||||
|
|
@ -690,7 +713,8 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
|
||||||
statement.RefTable = table
|
statement.RefTable = table
|
||||||
|
|
||||||
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
|
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
|
||||||
false, true, statement.allUseBool, statement.boolColumnMap)
|
false, true, statement.allUseBool, statement.useAllCols,
|
||||||
|
statement.mustColumnMap)
|
||||||
|
|
||||||
statement.ConditionStr = strings.Join(colNames, " AND ")
|
statement.ConditionStr = strings.Join(colNames, " AND ")
|
||||||
statement.BeanArgs = args
|
statement.BeanArgs = args
|
||||||
|
|
@ -729,7 +753,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}
|
||||||
statement.RefTable = table
|
statement.RefTable = table
|
||||||
|
|
||||||
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
|
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
|
||||||
true, statement.allUseBool, statement.boolColumnMap)
|
true, statement.allUseBool, statement.useAllCols, statement.mustColumnMap)
|
||||||
|
|
||||||
statement.ConditionStr = strings.Join(colNames, " AND ")
|
statement.ConditionStr = strings.Join(colNames, " AND ")
|
||||||
statement.BeanArgs = args
|
statement.BeanArgs = args
|
||||||
|
|
|
||||||
3985
tests/base_test.go
3985
tests/base_test.go
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +0,0 @@
|
||||||
go test -v -bench=. -run=XXX
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
go test -v -bench=. -run=XXX
|
|
||||||
|
|
@ -1,176 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BigStruct struct {
|
|
||||||
Id int64
|
|
||||||
Name string
|
|
||||||
Title string
|
|
||||||
Age string
|
|
||||||
Alias string
|
|
||||||
NickName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchDriverInsert(db *sql.DB, b *testing.B) {
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, err := db.Exec(`insert into big_struct (name, title, age, alias, nick_name)
|
|
||||||
values ('fafdasf', 'fadfa', 'afadfsaf', 'fadfafdsafd', 'fadfafdsaf')`)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchDriverFind(db *sql.DB, b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
_, err := db.Exec(`insert into big_struct (name, title, age, alias, nick_name)
|
|
||||||
values ('fafdasf', 'fadfa', 'afadfsaf', 'fadfafdsafd', 'fadfafdsaf')`)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N/50; i++ {
|
|
||||||
rows, err := db.Query("select * from big_struct limit 50")
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for rows.Next() {
|
|
||||||
s := &BigStruct{}
|
|
||||||
rows.Scan(&s.Id, &s.Name, &s.Title, &s.Age, &s.Alias, &s.NickName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchDriver(newdriver func() (*sql.DB, error), createTableSql,
|
|
||||||
dropTableSql string, opFunc func(*sql.DB, *testing.B), t *testing.B) {
|
|
||||||
db, err := newdriver()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(createTableSql)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
opFunc(db, t)
|
|
||||||
|
|
||||||
_, err = db.Exec(dropTableSql)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchInsert(engine *xorm.Engine, b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"}
|
|
||||||
err := engine.CreateTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
bs.Id = 0
|
|
||||||
_, err = engine.Insert(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
err = engine.DropTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchFind(engine *xorm.Engine, b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"}
|
|
||||||
err := engine.CreateTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
bs.Id = 0
|
|
||||||
_, err = engine.Insert(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N/50; i++ {
|
|
||||||
bss := new([]BigStruct)
|
|
||||||
err = engine.Limit(50).Find(bss)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
err = engine.DropTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBenchFindPtr(engine *xorm.Engine, b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"}
|
|
||||||
err := engine.CreateTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
bs.Id = 0
|
|
||||||
_, err = engine.Insert(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N/50; i++ {
|
|
||||||
bss := new([]*BigStruct)
|
|
||||||
err = engine.Limit(50).Find(bss)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
err = engine.DropTables(bs)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
//
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
_ "github.com/lunny/godbc"
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/caches"
|
|
||||||
)
|
|
||||||
|
|
||||||
const mssqlConnStr = "driver={SQL Server};Server=192.168.20.135;Database=xorm_test; uid=sa; pwd=1234;"
|
|
||||||
|
|
||||||
func newMssqlEngine() (*xorm.Engine, error) {
|
|
||||||
return xorm.NewEngine("odbc", mssqlConnStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMssql(t *testing.T) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMssqlWithCache(t *testing.T) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMssqlDriverDB() (*sql.DB, error) {
|
|
||||||
return sql.Open("odbc", mssqlConnStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
createTableMssql = `IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = 'big_struct' ) CREATE TABLE
|
|
||||||
"big_struct" ("id" BIGINT PRIMARY KEY IDENTITY NOT NULL, "name" VARCHAR(255) NULL, "title" VARCHAR(255) NULL,
|
|
||||||
"age" VARCHAR(255) NULL, "alias" VARCHAR(255) NULL, "nick_name" VARCHAR(255) NULL);
|
|
||||||
`
|
|
||||||
|
|
||||||
dropTableMssql = "IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'big_struct') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE IF EXISTS `big_struct`;"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkMssqlDriverInsert(t *testing.B) {
|
|
||||||
doBenchDriver(newMssqlDriverDB, createTableMssql, dropTableMssql,
|
|
||||||
doBenchDriverInsert, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlDriverFind(t *testing.B) {
|
|
||||||
doBenchDriver(newMssqlDriverDB, createTableMssql, dropTableMssql,
|
|
||||||
doBenchDriverFind, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlNoCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlNoCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlNoCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMssqlCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMssqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/caches"
|
|
||||||
_ "github.com/ziutek/mymysql/godrv"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET
|
|
||||||
utf8 COLLATE utf8_general_ci;
|
|
||||||
*/
|
|
||||||
|
|
||||||
var showTestSql bool = true
|
|
||||||
|
|
||||||
func TestMyMysql(t *testing.T) {
|
|
||||||
err := mymysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine, err := xorm.NewEngine("mymysql", "xorm_test/root/")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMyMysqlWithCache(t *testing.T) {
|
|
||||||
err := mymysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine, err := xorm.NewEngine("mymysql", "xorm_test2/root/")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMyMysqlEngine() (*xorm.Engine, error) {
|
|
||||||
return xorm.NewEngine("mymysql", "xorm_test2/root/")
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMyMysqlDriverDB() (*sql.DB, error) {
|
|
||||||
return sql.Open("mymysql", "xorm_test2/root/")
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlDriverInsert(t *testing.B) {
|
|
||||||
doBenchDriver(newMyMysqlDriverDB, createTableMySql, dropTableMySql,
|
|
||||||
doBenchDriverInsert, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlDriverFind(t *testing.B) {
|
|
||||||
doBenchDriver(newMyMysqlDriverDB, createTableMySql, dropTableMySql,
|
|
||||||
doBenchDriverFind, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mymysqlDdlImport() error {
|
|
||||||
engine, err := xorm.NewEngine("mymysql", "/root/")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
sqlResults, _ := engine.Import("testdata/mysql_ddl.sql")
|
|
||||||
engine.LogDebug("sql results: %v", sqlResults)
|
|
||||||
engine.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlNoCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer engine.Close()
|
|
||||||
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlNoCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer engine.Close()
|
|
||||||
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlNoCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer engine.Close()
|
|
||||||
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMyMysqlCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMyMysqlEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/caches"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET
|
|
||||||
utf8 COLLATE utf8_general_ci;
|
|
||||||
*/
|
|
||||||
|
|
||||||
func TestMysql(t *testing.T) {
|
|
||||||
err := mysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
engine, err := xorm.NewEngine("mysql", "root:@/xorm_test?charset=utf8")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMysqlSameMapper(t *testing.T) {
|
|
||||||
err := mysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
engine, err := xorm.NewEngine("mysql", "root:@/xorm_test1?charset=utf8")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMysqlWithCache(t *testing.T) {
|
|
||||||
err := mysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
engine, err := xorm.NewEngine("mysql", "root:@/xorm_test2?charset=utf8")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMysqlWithCacheSameMapper(t *testing.T) {
|
|
||||||
err := mysqlDdlImport()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
engine, err := xorm.NewEngine("mysql", "root:@/xorm_test3?charset=utf8")
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMysqlEngine() (*xorm.Engine, error) {
|
|
||||||
return xorm.NewEngine("mysql", "root:@/xorm_test?charset=utf8")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mysqlDdlImport() error {
|
|
||||||
engine, err := xorm.NewEngine("mysql", "root:@/?charset=utf8")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
sqlResults, _ := engine.Import("testdata/mysql_ddl.sql")
|
|
||||||
engine.LogDebug("sql results: %v", sqlResults)
|
|
||||||
engine.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMysqlDriverDB() (*sql.DB, error) {
|
|
||||||
return sql.Open("mysql", "root:@/xorm_test?charset=utf8")
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
createTableMySql = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR(255) NULL, `title` VARCHAR(255) NULL, `age` VARCHAR(255) NULL, `alias` VARCHAR(255) NULL, `nick_name` VARCHAR(255) NULL);"
|
|
||||||
dropTableMySql = "DROP TABLE IF EXISTS `big_struct`;"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkMysqlDriverInsert(t *testing.B) {
|
|
||||||
doBenchDriver(newMysqlDriverDB, createTableMySql, dropTableMySql,
|
|
||||||
doBenchDriverInsert, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlDriverFind(t *testing.B) {
|
|
||||||
doBenchDriver(newMysqlDriverDB, createTableMySql, dropTableMySql,
|
|
||||||
doBenchDriverFind, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlNoCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlNoCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlNoCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlCacheFind(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMysqlCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newMysqlEngine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/caches"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
//var connStr string = "dbname=xorm_test user=lunny password=1234 sslmode=disable"
|
|
||||||
|
|
||||||
var connStr string = "dbname=xorm_test sslmode=disable"
|
|
||||||
|
|
||||||
func newPostgresEngine() (*xorm.Engine, error) {
|
|
||||||
orm, err := xorm.NewEngine("postgres", connStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tables, err := orm.DBMetas()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, table := range tables {
|
|
||||||
_, err = orm.Exec("drop table \"" + table.Name + "\"")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return orm, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPostgresDriverDB() (*sql.DB, error) {
|
|
||||||
return sql.Open("postgres", connStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPostgres(t *testing.T) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer engine.Close()
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPostgresWithCache(t *testing.T) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
defer engine.Close()
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPostgresSameMapper(t *testing.T) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer engine.Close()
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPostgresWithCacheSameMapper(t *testing.T) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
defer engine.Close()
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
createTablePostgres = `CREATE TABLE IF NOT EXISTS "big_struct" ("id" SERIAL PRIMARY KEY NOT NULL, "name" VARCHAR(255) NULL, "title" VARCHAR(255) NULL, "age" VARCHAR(255) NULL, "alias" VARCHAR(255) NULL, "nick_name" VARCHAR(255) NULL);`
|
|
||||||
dropTablePostgres = `DROP TABLE IF EXISTS "big_struct";`
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkPostgresDriverInsert(t *testing.B) {
|
|
||||||
doBenchDriver(newPostgresDriverDB, createTablePostgres, dropTablePostgres,
|
|
||||||
doBenchDriverInsert, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresDriverFind(t *testing.B) {
|
|
||||||
doBenchDriver(newPostgresDriverDB, createTablePostgres, dropTablePostgres,
|
|
||||||
doBenchDriverFind, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresNoCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresNoCacheFind(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresNoCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresCacheInsert(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresCacheFind(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPostgresCacheFindPtr(t *testing.B) {
|
|
||||||
engine, err := newPostgresEngine()
|
|
||||||
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,183 +0,0 @@
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/caches"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newSqlite3Engine() (*xorm.Engine, error) {
|
|
||||||
os.Remove("./test.db")
|
|
||||||
return xorm.NewEngine("sqlite3", "./test.db")
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSqlite3DriverDB() (*sql.DB, error) {
|
|
||||||
os.Remove("./test.db")
|
|
||||||
return sql.Open("sqlite3", "./test.db")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSqlite3(t *testing.T) {
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSqlite3WithCache(t *testing.T) {
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSnakeMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSqlite3SameMapper(t *testing.T) {
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
testAll3(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSqlite3WithCacheSameMapper(t *testing.T) {
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetMapper(core.SameMapper{})
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
engine.ShowSQL = showTestSql
|
|
||||||
engine.ShowErr = showTestSql
|
|
||||||
engine.ShowWarn = showTestSql
|
|
||||||
engine.ShowDebug = showTestSql
|
|
||||||
|
|
||||||
testAll(engine, t)
|
|
||||||
testAllSameMapper(engine, t)
|
|
||||||
testAll2(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
createTableSqlite3 = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, `title` TEXT NULL, `age` TEXT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL);"
|
|
||||||
dropTableSqlite3 = "DROP TABLE IF EXISTS `big_struct`;"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkSqlite3DriverInsert(t *testing.B) {
|
|
||||||
doBenchDriver(newSqlite3DriverDB, createTableSqlite3, dropTableSqlite3,
|
|
||||||
doBenchDriverInsert, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3DriverFind(t *testing.B) {
|
|
||||||
doBenchDriver(newSqlite3DriverDB, createTableSqlite3, dropTableSqlite3,
|
|
||||||
doBenchDriverFind, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3NoCacheInsert(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3NoCacheFind(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3NoCacheFindPtr(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//engine.ShowSQL = true
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3CacheInsert(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
doBenchInsert(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3CacheFind(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
doBenchFind(engine, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSqlite3CacheFindPtr(t *testing.B) {
|
|
||||||
t.StopTimer()
|
|
||||||
engine, err := newSqlite3Engine()
|
|
||||||
defer engine.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
engine.SetDefaultCacher(xorm.NewLRUCacher(caches.NewMemoryStore(), 1000))
|
|
||||||
doBenchFindPtr(engine, t)
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
DROP DATABASE xorm_test;
|
|
||||||
DROP DATABASE xorm_test1;
|
|
||||||
DROP DATABASE xorm_test2;
|
|
||||||
DROP DATABASE xorm_test3;
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET utf8 COLLATE utf8_general_ci;
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test1 CHARACTER SET utf8 COLLATE utf8_general_ci;
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test2 CHARACTER SET utf8 COLLATE utf8_general_ci;
|
|
||||||
CREATE DATABASE IF NOT EXISTS xorm_test3 CHARACTER SET utf8 COLLATE utf8_general_ci;
|
|
||||||
40
xorm.go
40
xorm.go
|
|
@ -1,6 +1,7 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -9,16 +10,36 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lunny/xorm/caches"
|
"github.com/go-xorm/core"
|
||||||
"github.com/lunny/xorm/core"
|
"github.com/go-xorm/xorm/caches"
|
||||||
_ "github.com/lunny/xorm/dialects"
|
_ "github.com/go-xorm/xorm/drivers"
|
||||||
_ "github.com/lunny/xorm/drivers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version string = "0.4"
|
Version string = "0.4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
provided_dialects := map[string]struct {
|
||||||
|
dbType core.DbType
|
||||||
|
get func() core.Dialect
|
||||||
|
}{
|
||||||
|
"odbc": {"mssql", func() core.Dialect { return &mssql{} }},
|
||||||
|
"mysql": {"mysql", func() core.Dialect { return &mysql{} }},
|
||||||
|
"mymysql": {"mysql", func() core.Dialect { return &mysql{} }},
|
||||||
|
"oci8": {"oracle", func() core.Dialect { return &oracle{} }},
|
||||||
|
"postgres": {"postgres", func() core.Dialect { return &postgres{} }},
|
||||||
|
"sqlite3": {"sqlite3", func() core.Dialect { return &sqlite3{} }},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range provided_dialects {
|
||||||
|
_, err := sql.Open(string(k), "")
|
||||||
|
if err == nil {
|
||||||
|
core.RegisterDialect(v.dbType, v.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func close(engine *Engine) {
|
func close(engine *Engine) {
|
||||||
engine.Close()
|
engine.Close()
|
||||||
}
|
}
|
||||||
|
|
@ -46,19 +67,22 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
engine := &Engine{DriverName: driverName,
|
engine := &Engine{
|
||||||
DataSourceName: dataSourceName, dialect: dialect,
|
DriverName: driverName,
|
||||||
tableCachers: make(map[reflect.Type]core.Cacher)}
|
DataSourceName: dataSourceName,
|
||||||
|
dialect: dialect,
|
||||||
|
}
|
||||||
|
|
||||||
engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
|
engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
|
||||||
|
|
||||||
engine.Filters = dialect.Filters()
|
engine.Filters = dialect.Filters()
|
||||||
|
|
||||||
engine.Tables = make(map[reflect.Type]*core.Table)
|
engine.Tables = make(map[reflect.Type]*core.Table)
|
||||||
|
|
||||||
engine.mutex = &sync.RWMutex{}
|
engine.mutex = &sync.RWMutex{}
|
||||||
engine.TagIdentifier = "xorm"
|
engine.TagIdentifier = "xorm"
|
||||||
|
|
||||||
engine.Logger = os.Stdout
|
engine.Logger = NewSimpleLogger(os.Stdout)
|
||||||
|
|
||||||
//engine.Pool = NewSimpleConnectPool()
|
//engine.Pool = NewSimpleConnectPool()
|
||||||
//engine.Pool = NewNoneConnectPool()
|
//engine.Pool = NewNoneConnectPool()
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
[deps]
|
|
||||||
github.com/lunny/xorm=../
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
# xorm tools
|
|
||||||
|
|
||||||
|
|
||||||
xorm tools is a set of tools for database operation.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
`go get github.com/lunny/xorm/xorm`
|
|
||||||
|
|
||||||
and you should install the depends below:
|
|
||||||
|
|
||||||
* github.com/lunny/xorm
|
|
||||||
|
|
||||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
|
||||||
|
|
||||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
|
||||||
|
|
||||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
|
||||||
|
|
||||||
* Postgres: [github.com/bylevel/pq](https://github.com/bylevel/pq)
|
|
||||||
|
|
||||||
|
|
||||||
## Reverse
|
|
||||||
|
|
||||||
After you installed the tool, you can type
|
|
||||||
|
|
||||||
`xorm help reverse`
|
|
||||||
|
|
||||||
to get help
|
|
||||||
|
|
||||||
example:
|
|
||||||
|
|
||||||
sqlite:
|
|
||||||
`xorm reverse sqite3 test.db templates/goxorm`
|
|
||||||
|
|
||||||
mysql:
|
|
||||||
`xorm reverse mysql root:@/xorm_test?charset=utf8 templates/goxorm`
|
|
||||||
|
|
||||||
mymysql:
|
|
||||||
`xorm reverse mymysql xorm_test2/root/ templates/goxorm`
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
`xorm reverse postgres "dbname=xorm_test sslmode=disable" templates/goxorm`
|
|
||||||
|
|
||||||
will generated go files in `./model` directory
|
|
||||||
|
|
||||||
## Template and Config
|
|
||||||
|
|
||||||
Now, xorm tool supports go and c++ two languages and have go, goxorm, c++ three of default templates. In template directory, we can put a config file to control how to generating.
|
|
||||||
|
|
||||||
````
|
|
||||||
lang=go
|
|
||||||
genJson=1
|
|
||||||
```
|
|
||||||
|
|
||||||
lang must be go or c++ now.
|
|
||||||
genJson can be 1 or 0, if 1 then the struct will have json tag.
|
|
||||||
|
|
||||||
## LICENSE
|
|
||||||
|
|
||||||
BSD License
|
|
||||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
|
||||||
66
xorm/c++.go
66
xorm/c++.go
|
|
@ -1,66 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
//"fmt"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
CPlusTmpl LangTmpl = LangTmpl{
|
|
||||||
template.FuncMap{"Mapper": mapper.Table2Obj,
|
|
||||||
"Type": cPlusTypeStr,
|
|
||||||
"UnTitle": unTitle,
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
genCPlusImports,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func cPlusTypeStr(col *core.Column) string {
|
|
||||||
tp := col.SQLType
|
|
||||||
name := strings.ToUpper(tp.Name)
|
|
||||||
switch name {
|
|
||||||
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.Serial:
|
|
||||||
return "int"
|
|
||||||
case core.BigInt, core.BigSerial:
|
|
||||||
return "__int64"
|
|
||||||
case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText:
|
|
||||||
return "tstring"
|
|
||||||
case core.Date, core.DateTime, core.Time, core.TimeStamp:
|
|
||||||
return "time_t"
|
|
||||||
case core.Decimal, core.Numeric:
|
|
||||||
return "tstring"
|
|
||||||
case core.Real, core.Float:
|
|
||||||
return "float"
|
|
||||||
case core.Double:
|
|
||||||
return "double"
|
|
||||||
case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea:
|
|
||||||
return "tstring"
|
|
||||||
case core.Bool:
|
|
||||||
return "bool"
|
|
||||||
default:
|
|
||||||
return "tstring"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func genCPlusImports(tables []*core.Table) map[string]string {
|
|
||||||
imports := make(map[string]string)
|
|
||||||
|
|
||||||
for _, table := range tables {
|
|
||||||
for _, col := range table.Columns() {
|
|
||||||
switch cPlusTypeStr(col) {
|
|
||||||
case "time_t":
|
|
||||||
imports[`<time.h>`] = `<time.h>`
|
|
||||||
case "tstring":
|
|
||||||
imports["<string>"] = "<string>"
|
|
||||||
//case "__int64":
|
|
||||||
// imports[""] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imports
|
|
||||||
}
|
|
||||||
78
xorm/cmd.go
78
xorm/cmd.go
|
|
@ -1,78 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Command is an implementation of a go command
|
|
||||||
// like go build or go fix.
|
|
||||||
type Command struct {
|
|
||||||
// Run runs the command.
|
|
||||||
// The args are the arguments after the command name.
|
|
||||||
Run func(cmd *Command, args []string)
|
|
||||||
|
|
||||||
// UsageLine is the one-line usage message.
|
|
||||||
// The first word in the line is taken to be the command name.
|
|
||||||
UsageLine string
|
|
||||||
|
|
||||||
// Short is the short description shown in the 'go help' output.
|
|
||||||
Short string
|
|
||||||
|
|
||||||
// Long is the long message shown in the 'go help <this-command>' output.
|
|
||||||
Long string
|
|
||||||
|
|
||||||
// Flag is a set of flags specific to this command.
|
|
||||||
Flags map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the command's name: the first word in the usage line.
|
|
||||||
func (c *Command) Name() string {
|
|
||||||
name := c.UsageLine
|
|
||||||
i := strings.Index(name, " ")
|
|
||||||
if i >= 0 {
|
|
||||||
name = name[:i]
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) Usage() {
|
|
||||||
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runnable reports whether the command can be run; otherwise
|
|
||||||
// it is a documentation pseudo-command such as importpath.
|
|
||||||
func (c *Command) Runnable() bool {
|
|
||||||
return c.Run != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkFlags checks if the flag exists with correct format.
|
|
||||||
func checkFlags(flags map[string]bool, args []string, print func(string)) int {
|
|
||||||
num := 0 // Number of valid flags, use to cut out.
|
|
||||||
for i, f := range args {
|
|
||||||
// Check flag prefix '-'.
|
|
||||||
if !strings.HasPrefix(f, "-") {
|
|
||||||
// Not a flag, finish check process.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if it a valid flag.
|
|
||||||
if v, ok := flags[f]; ok {
|
|
||||||
flags[f] = !v
|
|
||||||
if !v {
|
|
||||||
print(f)
|
|
||||||
} else {
|
|
||||||
fmt.Println("DISABLE: " + f)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("[ERRO] Unknown flag: %s.\n", f)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
num = i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return num
|
|
||||||
}
|
|
||||||
260
xorm/go.go
260
xorm/go.go
|
|
@ -1,260 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"go/format"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
GoLangTmpl LangTmpl = LangTmpl{
|
|
||||||
template.FuncMap{"Mapper": mapper.Table2Obj,
|
|
||||||
"Type": typestring,
|
|
||||||
"Tag": tag,
|
|
||||||
"UnTitle": unTitle,
|
|
||||||
"gt": gt,
|
|
||||||
"getCol": getCol,
|
|
||||||
},
|
|
||||||
formatGo,
|
|
||||||
genGoImports,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errBadComparisonType = errors.New("invalid type for comparison")
|
|
||||||
errBadComparison = errors.New("incompatible types for comparison")
|
|
||||||
errNoComparison = errors.New("missing argument for comparison")
|
|
||||||
)
|
|
||||||
|
|
||||||
type kind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
invalidKind kind = iota
|
|
||||||
boolKind
|
|
||||||
complexKind
|
|
||||||
intKind
|
|
||||||
floatKind
|
|
||||||
integerKind
|
|
||||||
stringKind
|
|
||||||
uintKind
|
|
||||||
)
|
|
||||||
|
|
||||||
func basicKind(v reflect.Value) (kind, error) {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return boolKind, nil
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return intKind, nil
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return uintKind, nil
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return floatKind, nil
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return complexKind, nil
|
|
||||||
case reflect.String:
|
|
||||||
return stringKind, nil
|
|
||||||
}
|
|
||||||
return invalidKind, errBadComparisonType
|
|
||||||
}
|
|
||||||
|
|
||||||
// eq evaluates the comparison a == b || a == c || ...
|
|
||||||
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if len(arg2) == 0 {
|
|
||||||
return false, errNoComparison
|
|
||||||
}
|
|
||||||
for _, arg := range arg2 {
|
|
||||||
v2 := reflect.ValueOf(arg)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if k1 != k2 {
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
switch k1 {
|
|
||||||
case boolKind:
|
|
||||||
truth = v1.Bool() == v2.Bool()
|
|
||||||
case complexKind:
|
|
||||||
truth = v1.Complex() == v2.Complex()
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() == v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() == v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() == v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() == v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
if truth {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// lt evaluates the comparison a < b.
|
|
||||||
func lt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
v2 := reflect.ValueOf(arg2)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if k1 != k2 {
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
switch k1 {
|
|
||||||
case boolKind, complexKind:
|
|
||||||
return false, errBadComparisonType
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() < v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() < v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() < v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() < v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
return truth, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// le evaluates the comparison <= b.
|
|
||||||
func le(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// <= is < or ==.
|
|
||||||
lessThan, err := lt(arg1, arg2)
|
|
||||||
if lessThan || err != nil {
|
|
||||||
return lessThan, err
|
|
||||||
}
|
|
||||||
return eq(arg1, arg2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gt evaluates the comparison a > b.
|
|
||||||
func gt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// > is the inverse of <=.
|
|
||||||
lessOrEqual, err := le(arg1, arg2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return !lessOrEqual, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCol(cols map[string]*core.Column, name string) *core.Column {
|
|
||||||
return cols[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatGo(src string) (string, error) {
|
|
||||||
source, err := format.Source([]byte(src))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(source), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func genGoImports(tables []*core.Table) map[string]string {
|
|
||||||
imports := make(map[string]string)
|
|
||||||
|
|
||||||
for _, table := range tables {
|
|
||||||
for _, col := range table.Columns() {
|
|
||||||
if typestring(col) == "time.Time" {
|
|
||||||
imports["time"] = "time"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imports
|
|
||||||
}
|
|
||||||
|
|
||||||
func typestring(col *core.Column) string {
|
|
||||||
st := col.SQLType
|
|
||||||
t := core.SQLType2Type(st)
|
|
||||||
s := t.String()
|
|
||||||
if s == "[]uint8" {
|
|
||||||
return "[]byte"
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func tag(table *core.Table, col *core.Column) string {
|
|
||||||
isNameId := (mapper.Table2Obj(col.Name) == "Id")
|
|
||||||
isIdPk := isNameId && typestring(col) == "int64"
|
|
||||||
|
|
||||||
res := make([]string, 0)
|
|
||||||
if !col.Nullable {
|
|
||||||
if !isIdPk {
|
|
||||||
res = append(res, "not null")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if col.IsPrimaryKey {
|
|
||||||
if !isIdPk {
|
|
||||||
res = append(res, "pk")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if col.Default != "" {
|
|
||||||
res = append(res, "default "+col.Default)
|
|
||||||
}
|
|
||||||
if col.IsAutoIncrement {
|
|
||||||
if !isIdPk {
|
|
||||||
res = append(res, "autoincr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if col.IsCreated {
|
|
||||||
res = append(res, "created")
|
|
||||||
}
|
|
||||||
if col.IsUpdated {
|
|
||||||
res = append(res, "updated")
|
|
||||||
}
|
|
||||||
for name, _ := range col.Indexes {
|
|
||||||
index := table.Indexes[name]
|
|
||||||
var uistr string
|
|
||||||
if index.Type == core.UniqueType {
|
|
||||||
uistr = "unique"
|
|
||||||
} else if index.Type == core.IndexType {
|
|
||||||
uistr = "index"
|
|
||||||
}
|
|
||||||
if len(index.Cols) > 1 {
|
|
||||||
uistr += "(" + index.Name + ")"
|
|
||||||
}
|
|
||||||
res = append(res, uistr)
|
|
||||||
}
|
|
||||||
|
|
||||||
nstr := col.SQLType.Name
|
|
||||||
if col.Length != 0 {
|
|
||||||
if col.Length2 != 0 {
|
|
||||||
nstr += fmt.Sprintf("(%v, %v)", col.Length, col.Length2)
|
|
||||||
} else {
|
|
||||||
nstr += fmt.Sprintf("(%v)", col.Length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = append(res, nstr)
|
|
||||||
|
|
||||||
var tags []string
|
|
||||||
if genJson {
|
|
||||||
tags = append(tags, "json:\""+col.Name+"\"")
|
|
||||||
}
|
|
||||||
if len(res) > 0 {
|
|
||||||
tags = append(tags, "xorm:\""+strings.Join(res, " ")+"\"")
|
|
||||||
}
|
|
||||||
if len(tags) > 0 {
|
|
||||||
return "`" + strings.Join(tags, " ") + "`"
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
51
xorm/lang.go
51
xorm/lang.go
|
|
@ -1,51 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LangTmpl struct {
|
|
||||||
Funcs template.FuncMap
|
|
||||||
Formater func(string) (string, error)
|
|
||||||
GenImports func([]*core.Table) map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
mapper = &core.SnakeMapper{}
|
|
||||||
langTmpls = map[string]LangTmpl{
|
|
||||||
"go": GoLangTmpl,
|
|
||||||
"c++": CPlusTmpl,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadConfig(f string) map[string]string {
|
|
||||||
bts, err := ioutil.ReadFile(f)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
configs := make(map[string]string)
|
|
||||||
lines := strings.Split(string(bts), "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimRight(line, "\r")
|
|
||||||
vs := strings.Split(line, "=")
|
|
||||||
if len(vs) == 2 {
|
|
||||||
configs[strings.TrimSpace(vs[0])] = strings.TrimSpace(vs[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return configs
|
|
||||||
}
|
|
||||||
|
|
||||||
func unTitle(src string) string {
|
|
||||||
if src == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(src) == 1 {
|
|
||||||
return strings.ToLower(string(src[0]))
|
|
||||||
} else {
|
|
||||||
return strings.ToLower(string(src[0])) + src[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
270
xorm/reverse.go
270
xorm/reverse.go
|
|
@ -1,270 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
_ "github.com/bylevel/pq"
|
|
||||||
"github.com/dvirsky/go-pylog/logging"
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"github.com/lunny/xorm/core"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
_ "github.com/ziutek/mymysql/godrv"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CmdReverse = &Command{
|
|
||||||
UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]",
|
|
||||||
Short: "reverse a db to codes",
|
|
||||||
Long: `
|
|
||||||
according database's tables and columns to generate codes for Go, C++ and etc.
|
|
||||||
|
|
||||||
-m Generated one go file for every table
|
|
||||||
driverName Database driver name, now supported four: mysql mymysql sqlite3 postgres
|
|
||||||
datasourceName Database connection uri, for detail infomation please visit driver's project page
|
|
||||||
tmplPath Template dir for generated. the default templates dir has provide 1 template
|
|
||||||
generatedPath This parameter is optional, if blank, the default value is model, then will
|
|
||||||
generated all codes in model dir
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
CmdReverse.Run = runReverse
|
|
||||||
CmdReverse.Flags = map[string]bool{
|
|
||||||
"-s": false,
|
|
||||||
"-l": false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
genJson bool = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func printReversePrompt(flag string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tmpl struct {
|
|
||||||
Tables []*core.Table
|
|
||||||
Imports map[string]string
|
|
||||||
Model string
|
|
||||||
}
|
|
||||||
|
|
||||||
func dirExists(dir string) bool {
|
|
||||||
d, e := os.Stat(dir)
|
|
||||||
switch {
|
|
||||||
case e != nil:
|
|
||||||
return false
|
|
||||||
case !d.IsDir():
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func runReverse(cmd *Command, args []string) {
|
|
||||||
num := checkFlags(cmd.Flags, args, printReversePrompt)
|
|
||||||
if num == -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
args = args[num:]
|
|
||||||
|
|
||||||
if len(args) < 3 {
|
|
||||||
fmt.Println("params error, please see xorm help reverse")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var isMultiFile bool = true
|
|
||||||
if use, ok := cmd.Flags["-s"]; ok {
|
|
||||||
isMultiFile = !use
|
|
||||||
}
|
|
||||||
|
|
||||||
curPath, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(curPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var genDir string
|
|
||||||
var model string
|
|
||||||
if len(args) == 4 {
|
|
||||||
|
|
||||||
genDir, err = filepath.Abs(args[3])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
model = path.Base(genDir)
|
|
||||||
} else {
|
|
||||||
model = "model"
|
|
||||||
genDir = path.Join(curPath, model)
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err := filepath.Abs(args[2])
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dirExists(dir) {
|
|
||||||
logging.Error("Template %v path is not exist", dir)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var langTmpl LangTmpl
|
|
||||||
var ok bool
|
|
||||||
var lang string = "go"
|
|
||||||
|
|
||||||
cfgPath := path.Join(dir, "config")
|
|
||||||
info, err := os.Stat(cfgPath)
|
|
||||||
var configs map[string]string
|
|
||||||
if err == nil && !info.IsDir() {
|
|
||||||
configs = loadConfig(cfgPath)
|
|
||||||
if l, ok := configs["lang"]; ok {
|
|
||||||
lang = l
|
|
||||||
}
|
|
||||||
if j, ok := configs["genJson"]; ok {
|
|
||||||
genJson, err = strconv.ParseBool(j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if langTmpl, ok = langTmpls[lang]; !ok {
|
|
||||||
fmt.Println("Unsupported programing language", lang)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
os.MkdirAll(genDir, os.ModePerm)
|
|
||||||
|
|
||||||
Orm, err := xorm.NewEngine(args[0], args[1])
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tables, err := Orm.DBMetas()
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
|
|
||||||
if info.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.Name() == "config" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
bs, err := ioutil.ReadFile(f)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.New(f)
|
|
||||||
t.Funcs(langTmpl.Funcs)
|
|
||||||
|
|
||||||
tmpl, err := t.Parse(string(bs))
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var w *os.File
|
|
||||||
fileName := info.Name()
|
|
||||||
newFileName := fileName[:len(fileName)-4]
|
|
||||||
ext := path.Ext(newFileName)
|
|
||||||
|
|
||||||
if !isMultiFile {
|
|
||||||
w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
imports := langTmpl.GenImports(tables)
|
|
||||||
|
|
||||||
tbls := make([]*core.Table, 0)
|
|
||||||
for _, table := range tables {
|
|
||||||
tbls = append(tbls, table)
|
|
||||||
}
|
|
||||||
|
|
||||||
newbytes := bytes.NewBufferString("")
|
|
||||||
|
|
||||||
t := &Tmpl{Tables: tbls, Imports: imports, Model: model}
|
|
||||||
err = tmpl.Execute(newbytes, t)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tplcontent, err := ioutil.ReadAll(newbytes)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var source string
|
|
||||||
if langTmpl.Formater != nil {
|
|
||||||
source, err = langTmpl.Formater(string(tplcontent))
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
source = string(tplcontent)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteString(source)
|
|
||||||
w.Close()
|
|
||||||
} else {
|
|
||||||
for _, table := range tables {
|
|
||||||
// imports
|
|
||||||
tbs := []*core.Table{table}
|
|
||||||
imports := langTmpl.GenImports(tbs)
|
|
||||||
|
|
||||||
w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newbytes := bytes.NewBufferString("")
|
|
||||||
|
|
||||||
t := &Tmpl{Tables: tbs, Imports: imports, Model: model}
|
|
||||||
err = tmpl.Execute(newbytes, t)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tplcontent, err := ioutil.ReadAll(newbytes)
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var source string
|
|
||||||
if langTmpl.Formater != nil {
|
|
||||||
source, err = langTmpl.Formater(string(tplcontent))
|
|
||||||
if err != nil {
|
|
||||||
logging.Error("%v-%v", err, string(tplcontent))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
source = string(tplcontent)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteString(source)
|
|
||||||
w.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
147
xorm/shell.go
147
xorm/shell.go
|
|
@ -1,147 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/lunny/xorm"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CmdShell = &Command{
|
|
||||||
UsageLine: "shell driverName datasourceName",
|
|
||||||
Short: "a general shell to operate all kinds of database",
|
|
||||||
Long: `
|
|
||||||
general database's shell for sqlite3, mysql, postgres.
|
|
||||||
|
|
||||||
driverName Database driver name, now supported four: mysql mymysql sqlite3 postgres
|
|
||||||
datasourceName Database connection uri, for detail infomation please visit driver's project page
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
CmdShell.Run = runShell
|
|
||||||
CmdShell.Flags = map[string]bool{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var engine *xorm.Engine
|
|
||||||
|
|
||||||
func shellHelp() {
|
|
||||||
fmt.Println(`
|
|
||||||
show tables show all tables
|
|
||||||
columns <table_name> show table's column info
|
|
||||||
indexes <table_name> show table's index info
|
|
||||||
exit exit shell
|
|
||||||
source <sql_file> exec sql file to current database
|
|
||||||
dump [-nodata] <sql_file> dump structs or records to sql file
|
|
||||||
help show this document
|
|
||||||
<statement> SQL statement
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runShell(cmd *Command, args []string) {
|
|
||||||
if len(args) != 2 {
|
|
||||||
fmt.Println("params error, please see xorm help shell")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
engine, err = xorm.NewEngine(args[0], args[1])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = engine.Ping()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var scmd string
|
|
||||||
fmt.Print("xorm$ ")
|
|
||||||
for {
|
|
||||||
var input string
|
|
||||||
_, err := fmt.Scan(&input)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.ToLower(input) == "exit" {
|
|
||||||
fmt.Println("bye")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(input, ";") {
|
|
||||||
scmd = scmd + " " + input
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
scmd = scmd + " " + input
|
|
||||||
lcmd := strings.TrimSpace(strings.ToLower(scmd))
|
|
||||||
if strings.HasPrefix(lcmd, "select") {
|
|
||||||
res, err := engine.Query(scmd + "\n")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
} else {
|
|
||||||
if len(res) <= 0 {
|
|
||||||
fmt.Println("no records")
|
|
||||||
} else {
|
|
||||||
columns := make(map[string]int)
|
|
||||||
for k, _ := range res[0] {
|
|
||||||
columns[k] = len(k)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range res {
|
|
||||||
for k, s := range m {
|
|
||||||
l := len(string(s))
|
|
||||||
if l > columns[k] {
|
|
||||||
columns[k] = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxlen = 0
|
|
||||||
for _, l := range columns {
|
|
||||||
maxlen = maxlen + l + 3
|
|
||||||
}
|
|
||||||
maxlen = maxlen + 1
|
|
||||||
|
|
||||||
fmt.Println(strings.Repeat("-", maxlen))
|
|
||||||
fmt.Print("|")
|
|
||||||
slice := make([]string, 0)
|
|
||||||
for k, l := range columns {
|
|
||||||
fmt.Print(" " + k + " ")
|
|
||||||
fmt.Print(strings.Repeat(" ", l-len(k)))
|
|
||||||
fmt.Print("|")
|
|
||||||
slice = append(slice, k)
|
|
||||||
}
|
|
||||||
fmt.Print("\n")
|
|
||||||
for _, r := range res {
|
|
||||||
fmt.Print("|")
|
|
||||||
for _, k := range slice {
|
|
||||||
fmt.Print(" " + string(r[k]) + " ")
|
|
||||||
fmt.Print(strings.Repeat(" ", columns[k]-len(string(r[k]))))
|
|
||||||
fmt.Print("|")
|
|
||||||
}
|
|
||||||
fmt.Print("\n")
|
|
||||||
}
|
|
||||||
fmt.Println(strings.Repeat("-", maxlen))
|
|
||||||
//fmt.Println(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if lcmd == "show tables;" {
|
|
||||||
/*tables, err := engine.DBMetas()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}*/
|
|
||||||
} else {
|
|
||||||
cnt, err := engine.Exec(scmd)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("%d records changed.\n", cnt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scmd = ""
|
|
||||||
fmt.Print("xorm$ ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
{{ range .Imports}}
|
|
||||||
#include {{.}}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{range .Tables}}class {{Mapper .Name}} {
|
|
||||||
{{$table := .}}
|
|
||||||
public:
|
|
||||||
{{range .Columns}}{{$name := Mapper .Name}} {{Type .}} Get{{Mapper .Name}}() {
|
|
||||||
return this->m_{{UnTitle $name}};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Set{{$name}}({{Type .}} {{UnTitle $name}}) {
|
|
||||||
this->m_{{UnTitle $name}} = {{UnTitle $name}};
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}private:
|
|
||||||
{{range .Columns}}{{$name := Mapper .Name}} {{Type .}} m_{{UnTitle $name}};
|
|
||||||
{{end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
lang=c++
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
lang=go
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package {{.Model}}
|
|
||||||
|
|
||||||
import (
|
|
||||||
{{range .Imports}}"{{.}}"{{end}}
|
|
||||||
)
|
|
||||||
|
|
||||||
{{range .Tables}}
|
|
||||||
type {{Mapper .Name}} struct {
|
|
||||||
{{$table := .}}
|
|
||||||
{{range .Columns}} {{Mapper .Name}} {{Type .}}
|
|
||||||
{{end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
lang=go
|
|
||||||
genJson=0
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package {{.Model}}
|
|
||||||
|
|
||||||
{{$ilen := len .Imports}}
|
|
||||||
{{if gt $ilen 0}}
|
|
||||||
import (
|
|
||||||
{{range .Imports}}"{{.}}"{{end}}
|
|
||||||
)
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{range .Tables}}
|
|
||||||
type {{Mapper .Name}} struct {
|
|
||||||
{{$table := .}}
|
|
||||||
{{$columns := .Columns}}
|
|
||||||
{{range .ColumnsSeq}}{{$col := getCol $columns .}} {{Mapper $col.Name}} {{Type $col}} {{Tag $table $col}}
|
|
||||||
{{end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
162
xorm/xorm.go
162
xorm/xorm.go
|
|
@ -1,162 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/dvirsky/go-pylog/logging"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"text/template"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// +build go1.1
|
|
||||||
|
|
||||||
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
|
|
||||||
const go11tag = true
|
|
||||||
|
|
||||||
const version = "0.1"
|
|
||||||
|
|
||||||
// Commands lists the available commands and help topics.
|
|
||||||
// The order here is the order in which they are printed by 'gopm help'.
|
|
||||||
var commands = []*Command{
|
|
||||||
CmdReverse,
|
|
||||||
CmdShell,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
logging.SetLevel(logging.ALL)
|
|
||||||
// Check length of arguments.
|
|
||||||
args := os.Args[1:]
|
|
||||||
if len(args) < 1 {
|
|
||||||
usage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show help documentation.
|
|
||||||
if args[0] == "help" {
|
|
||||||
help(args[1:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check commands and run.
|
|
||||||
for _, comm := range commands {
|
|
||||||
if comm.Name() == args[0] && comm.Run != nil {
|
|
||||||
comm.Run(comm, args[1:])
|
|
||||||
exit()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "xorm: unknown subcommand %q\nRun 'xorm help' for usage.\n", args[0])
|
|
||||||
setExitStatus(2)
|
|
||||||
exit()
|
|
||||||
}
|
|
||||||
|
|
||||||
var exitStatus = 0
|
|
||||||
var exitMu sync.Mutex
|
|
||||||
|
|
||||||
func setExitStatus(n int) {
|
|
||||||
exitMu.Lock()
|
|
||||||
if exitStatus < n {
|
|
||||||
exitStatus = n
|
|
||||||
}
|
|
||||||
exitMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
var usageTemplate = `xorm is a database tool based xorm package.
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
xorm command [arguments]
|
|
||||||
|
|
||||||
The commands are:
|
|
||||||
{{range .}}{{if .Runnable}}
|
|
||||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
|
||||||
|
|
||||||
Use "xorm help [command]" for more information about a command.
|
|
||||||
|
|
||||||
Additional help topics:
|
|
||||||
{{range .}}{{if not .Runnable}}
|
|
||||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
|
||||||
|
|
||||||
Use "xorm help [topic]" for more information about that topic.
|
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
var helpTemplate = `{{if .Runnable}}usage: xorm {{.UsageLine}}
|
|
||||||
|
|
||||||
{{end}}{{.Long | trim}}
|
|
||||||
`
|
|
||||||
|
|
||||||
// tmpl executes the given template text on data, writing the result to w.
|
|
||||||
func tmpl(w io.Writer, text string, data interface{}) {
|
|
||||||
t := template.New("top")
|
|
||||||
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
|
||||||
template.Must(t.Parse(text))
|
|
||||||
if err := t.Execute(w, data); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func capitalize(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
r, n := utf8.DecodeRuneInString(s)
|
|
||||||
return string(unicode.ToTitle(r)) + s[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func printUsage(w io.Writer) {
|
|
||||||
tmpl(w, usageTemplate, commands)
|
|
||||||
}
|
|
||||||
|
|
||||||
func usage() {
|
|
||||||
printUsage(os.Stderr)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// help implements the 'help' command.
|
|
||||||
func help(args []string) {
|
|
||||||
if len(args) == 0 {
|
|
||||||
printUsage(os.Stdout)
|
|
||||||
// not exit 2: succeeded at 'gopm help'.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(args) != 1 {
|
|
||||||
fmt.Fprintf(os.Stderr, "usage: xorm help command\n\nToo many arguments given.\n")
|
|
||||||
os.Exit(2) // failed at 'gopm help'
|
|
||||||
}
|
|
||||||
|
|
||||||
arg := args[0]
|
|
||||||
|
|
||||||
for _, cmd := range commands {
|
|
||||||
if cmd.Name() == arg {
|
|
||||||
tmpl(os.Stdout, helpTemplate, cmd)
|
|
||||||
// not exit 2: succeeded at 'gopm help cmd'.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'xorm help'.\n", arg)
|
|
||||||
os.Exit(2) // failed at 'gopm help cmd'
|
|
||||||
}
|
|
||||||
|
|
||||||
var atexitFuncs []func()
|
|
||||||
|
|
||||||
func atexit(f func()) {
|
|
||||||
atexitFuncs = append(atexitFuncs, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func exit() {
|
|
||||||
for _, f := range atexitFuncs {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
os.Exit(exitStatus)
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue