add sql execution support

This commit is contained in:
Lunny Xiao 2013-05-08 21:42:22 +08:00
parent 74e0e3b175
commit 5870dbaab0
8 changed files with 574 additions and 320 deletions

141
README.md
View File

@ -7,12 +7,10 @@ xorm is an ORM for Go. It lets you map Go structs to tables in a database.
Right now, it interfaces with Mysql/SQLite. The goal however is to add support for PostgreSQL/DB2/MS ADODB/ODBC/Oracle in the future.
All in all, it's not entirely ready for advanced use yet, but it's getting there.
All in all, it's not entirely ready for product use yet, but it's getting there.
Drivers for Go's sql package which support database/sql includes:
Mysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL)
SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
@ -55,19 +53,45 @@ then, insert an struct to table
or you want to update this struct
user := User{Id:1, Name:"xlw"}
rows, err := engine.Update(&user)
user := User{Name:"xlw"}
rows, err := engine.Update(&user, &User{Id:1})
// rows, err := engine.Where("id = ?", 1).Update(&user)
3.Fetch a single object by user
var user = User{Id:27}
engine.Get(&user)
err := engine.Get(&user)
var user = User{Name:"xlw"}
engine.Get(&user)
err := engine.Get(&user)
4.Fetch multipe objects, use Find
var allusers []Userinfo
err := engine.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20
var tenusers []Userinfo
err := engine.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 if omit offset the default is 0
var everyone []Userinfo
err := engine.Find(&everyone)
5.Delete and Count
err := engine.Delete(&User{Id:1})
total, err := engine.Count(&User{Name:"xlw"})
##Origin Use
Of course, the basic usage is also provided.
sql := "select * from userinfo"
results, err := engine.Query(sql)
sql = "update userinfo set username=? where id=?"
res, err := engine.Exec(sql, "xiaolun", 1)
##Deep Use
for deep use, you should create a session, this func will create a connection to db
@ -82,49 +106,120 @@ for deep use, you should create a session, this func will create a connection to
1.Fetch a single object by where
var user Userinfo
session.Where("id=?", 27).Get(&user)
var user2 Userinfo
session.Where(3).Get(&user2) // this is shorthand for the version above
var user3 Userinfo
session.Where("name = ?", "john").Get(&user3) // more complex query
var user4 Userinfo
var user3 Userinfo
session.Where("name = ? and age < ?", "john", 88).Get(&user4) // even more complex
2.Fetch multiple objects
var allusers []Userinfo
err := session.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20
var tenusers []Userinfo
err := session.Where("id > ?", "3").Limit(10).Find(&tenusers) //Get id>3 limit 10 if omit offset the default is 0
err := session.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 if omit offset the default is 0
var everyone []Userinfo
err := session.Find(&everyone)
3.Transaction
##***Mapping Rules***
// add Begin() before any action
session.Begin()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
if err != nil {
session.Rollback()
return
}
_, err = session.Delete(&user2)
if err != nil {
session.Rollback()
return
}
// add Commit() after all actions
err = session.Commit()
if err != nil {
return
}
4.Mixed Transaction
// add Begin() before any action
session.Begin()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
if err != nil {
session.Rollback()
return
}
_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
if err != nil {
session.Rollback()
return
}
// add Commit() after all actions
err = session.Commit()
if err != nil {
return
}
##Mapping Rules
1.Struct and struct's fields name should be Pascal style, and the table and column's name default is us
for example:
For example:
The structs Name 'UserInfo' will turn into the table name 'user_info', the same as the keyname.
If the keyname is 'UserName' will turn into the select colum 'user_name'
2.You have two method to change the rule. One is implement your own Map interface according IMapper, you can find the interface in mapper.go and set it to engine.Mapper
another is use field tag, field tag support the below keywords:
* [name] column name
* pk the field is a primary key
* int(11)/varchar(50) column type
* autoincr auto incrment
* [not ]null if column can be null value
* unique unique
* \- this field is not map as a table column
<table>
<tr>
<td>name</td><td>column name</td>
</tr>
<tr>
<td>pk</td><td>the field is a primary key</td>
</tr>
<tr>
<td>int(11)/varchar(50)</td><td>column type</td>
</tr>
<tr>
<td>autoincr</td><td>auto incrment</td>
</tr>
<tr>
<td>[not ]null</td><td>if column can be null value</td>
</tr>
<tr>
<td>unique</td><td>unique</td>
</tr>
<tr>
<td>-</td><td>this field is not map as a table column</td>
</tr>
</table>
##FAQ
1.How the xorm tag use both with json?

View File

@ -1,127 +1,234 @@
xorm
=====
# xorm
===========
[English](README.md)
xorm 是一个Go语言的ORM对象关系模型. It lets you map Go structs to tables in a database.
xorm是一个Go语言的ORM库. 通过它可以简化对数据库的操作。
Right now, it interfaces with Mysql/SQLite. The goal however is to add support for PostgreSQL/DB2/MS ADODB/ODBC/Oracle in the future.
目前仅支持Mysql和SQLite当然我们的目标是支持PostgreSQL/DB2/MS ADODB/ODBC/Oracle等等。
All in all, it's not entirely ready for advanced use yet, but it's getting there.
但是,目前的版本还不可用于正式版本。
Drivers for Go's sql package which support database/sql includes:
Mysql:[github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
目前支持的Go数据库驱动如下
Mysql: [github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL)
SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
### Installing xorm
## 安装
go get github.com/lunny/xorm
### Quick Start
## 快速开始
1. Create an database engine (for example: mysql)
1.创建数据库引擎 (例如: mysql)
```go
engine := xorm.Create("mysql://root:123@localhost/test")
```
2. Define your struct
```go
2.定义你的Struct
type User struct {
Id int
Name string
Age int `xorm:"-"`
}
```
for Simple Task, just use engine's functions:
begin start, you should create a database and then we create the tables
对于简单的任务可以只用engine一个对象就可以完成操作。
首先需要创建一个数据库然后使用以下语句创建一个Struct对应的表。
```go
err := engine.CreateTables(&User{})
```
then, insert an struct to table
```go
然后,可以将一个结构体作为一条记录插入到表中。
id, err := engine.Insert(&User{Name:"lunny"})
```
or you want to update this struct
```go
user := User{Id:1, Name:"xlw"}
rows, err := engine.Update(&user)
```
或者执行更新操作:
user := User{Name:"xlw"}
rows, err := engine.Update(&user, &User{Id:1})
// rows, err := engine.Where("id = ?", 1).Update(&user)
3.获取单个对象可以用Get方法
3. Fetch a single object by user
```go
var user = User{Id:27}
engine.Get(&user)
err := engine.Get(&user)
var user = User{Name:"xlw"}
engine.Get(&user)
```
err := engine.Get(&user)
4.获取多个对象可以用Find方法
var allusers []Userinfo
err := engine.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20
var tenusers []Userinfo
err := engine.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 if omit offset the default is 0
var everyone []Userinfo
err := engine.Find(&everyone)
5.另外还有Delete和Count方法
err := engine.Delete(&User{Id:1})
total, err := engine.Count(&User{Name:"xlw"})
##Origin Use
当然如果你想直接使用SQL语句进行操作也是允许的。
sql := "select * from userinfo"
results, err := engine.Query(sql)
sql = "update userinfo set username=? where id=?"
res, err := engine.Exec(sql, "xiaolun", 1)
##Deep Use
更高级的用法我们必须要使用session对象session对象在创建时会创建一个数据库连接。
for deep use, you should create a session, this func will create a connection to db
```go
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
return
}
```
1. Fetch a single object by where
```go
1.session对象同样也可以查询
var user Userinfo
session.Where("id=?", 27).Get(&user)
var user2 Userinfo
session.Where(3).Get(&user2) // this is shorthand for the version above
var user3 Userinfo
session.Where("name = ?", "john").Get(&user3) // more complex query
var user4 Userinfo
var user3 Userinfo
session.Where("name = ? and age < ?", "john", 88).Get(&user4) // even more complex
```
2. Fetch multiple objects
```go
2.获取多个对象
var allusers []Userinfo
err := session.Where("id > ?", "3").Limit(10,20).Find(&allusers) //Get id>3 limit 10 offset 20
var tenusers []Userinfo
err := session.Where("id > ?", "3").Limit(10).Find(&tenusers) //Get id>3 limit 10 if omit offset the default is 0
err := session.Limit(10).Find(&tenusers, &Userinfo{Name:"xlw"}) //Get All Name="xlw" limit 10 if omit offset the default is 0
var everyone []Userinfo
err := session.Find(&everyone)
```
###***About Map Rules***
1. Struct and struct's fields name should be Pascal style, and the table and column's name default is us
for example:
The structs Name 'UserInfo' will turn into the table name 'user_info', the same as the keyname.
If the keyname is 'UserName' will turn into the select colum 'user_name'
3.事务处理
2. You have two method to change the rule. One is implement your own Map interface according IMapper, you can find the interface in mapper.go and set it to engine.Mapper
// add Begin() before any action
session.Begin()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
if err != nil {
session.Rollback()
return
}
another is use field tag, field tag support the below keywords:
[name] column name
pk the field is a primary key
int(11)/varchar(50) column type
autoincr auto incrment
[not ]null if column can be null value
unique unique
- this field is not map as a table column
_, err = session.Delete(&user2)
if err != nil {
session.Rollback()
return
}
// add Commit() after all actions
err = session.Commit()
if err != nil {
return
}
4.混合型事务这个事务中既有直接的SQL语句又有其它方法
// add Begin() before any action
session.Begin()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
if err != nil {
session.Rollback()
return
}
_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
if err != nil {
session.Rollback()
return
}
// add Commit() after all actions
err = session.Commit()
if err != nil {
return
}
##Mapping Rules
1.Struct 和 Struct 的field名字应该为Pascal式命名默认的映射规则将转换成用下划线连接的命名规则这个映射是自动进行的当然你可以通过修改Engine或者Session的成员IMapper来改变它。
例如:
结构体的名字UserInfo将会自动对应数据库中的名为user_info的表。
UserInfo中的成员UserName将会自动对应名为user_name的字段。
2.当然你也可以改变这个规则这有两种方法。一是实现你自己的IMapper你可以在mapper.go中查看到这个借口。然后设置到 engine.Mapper这将影响所有的Session或者你可以设置到某一个session那么只会影响到这个session对应的操作。
另外一种方法就通过Field Tag来进行改变关于Field Tag请参考Go的语言文档如下列出了Tag中可用的关键字及其对应的意义
<table>
<tr>
<td>name</td><td>当前field对应的字段的名称可选</td>
</tr>
<tr>
<td>pk</td><td>是否是Primary Key</td>
</tr>
<tr>
<td>int(11)/varchar(50)</td><td>字段类型</td>
</tr>
<tr>
<td>autoincr</td><td>是否是自增</td>
</tr>
<tr>
<td>[not ]null</td><td>是否可以为空</td>
</tr>
<tr>
<td>unique</td><td>是否是唯一</td>
</tr>
<tr>
<td>-</td><td>这个Field将不进行字段映射</td>
</tr>
</table>
##FAQ
1.xorm的tag和json的tag如何同时起作用
使用空格分开
type User struct {
User string `json:"user" orm:"user_id"`
}
## LICENSE

View File

@ -341,6 +341,24 @@ func (e *Engine) CreateAll() error {
return err
}
func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) {
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
return nil, err
}
return session.Exec(sql, args...)
}
func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
return nil, err
}
return session.Query(sql, paramStr...)
}
func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
session, err := engine.MakeSession()
defer session.Close()
@ -348,21 +366,19 @@ func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
return -1, err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
session.Statement = engine.Statement
return session.Insert(beans...)
}
func (engine *Engine) Update(bean interface{}) (int64, error) {
func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) {
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
return -1, err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
return session.Update(bean)
session.Statement = engine.Statement
return session.Update(bean, condiBeans...)
}
func (engine *Engine) Delete(bean interface{}) (int64, error) {
@ -372,8 +388,7 @@ func (engine *Engine) Delete(bean interface{}) (int64, error) {
return -1, err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
session.Statement = engine.Statement
return session.Delete(bean)
}
@ -384,21 +399,19 @@ func (engine *Engine) Get(bean interface{}) error {
return err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
session.Statement = engine.Statement
return session.Get(bean)
}
func (engine *Engine) Find(beans interface{}) error {
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
return err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
return session.Find(beans)
session.Statement = engine.Statement
return session.Find(beans, condiBeans...)
}
func (engine *Engine) Count(bean interface{}) (int64, error) {
@ -408,7 +421,6 @@ func (engine *Engine) Count(bean interface{}) (int64, error) {
return 0, err
}
defer engine.Statement.Init()
engine.Statement.Session = &session
session.SetStatement(&engine.Statement)
session.Statement = engine.Statement
return session.Count(bean)
}

View File

@ -38,94 +38,72 @@ type Session struct {
Db *sql.DB
Engine *Engine
Tx *sql.Tx
Statements []Statement
Statement Statement
Mapper IMapper
IsAutoCommit bool
IsAutoRollback bool
CurStatementIdx int
}
func (session *Session) Init() {
session.Statements = make([]Statement, 0)
session.CurStatementIdx = -1
session.Statement = Statement{}
session.IsAutoCommit = true
session.IsAutoRollback = false
}
func (session *Session) Close() {
rollbackfunc := func() {
if session.IsAutoRollback {
session.Rollback()
}
}
defer rollbackfunc()
defer session.Db.Close()
}
func (session *Session) CurrentStatement() *Statement {
if session.CurStatementIdx > -1 {
return &session.Statements[session.CurStatementIdx]
}
return nil
}
func (session *Session) AutoStatement() *Statement {
if session.CurStatementIdx == -1 {
session.newStatement()
}
return session.CurrentStatement()
}
func (session *Session) Where(querystring string, args ...interface{}) *Session {
statement := session.AutoStatement()
statement.Where(querystring, args...)
session.Statement.Where(querystring, args...)
return session
}
func (session *Session) Limit(limit int, start ...int) *Session {
statement := session.AutoStatement()
statement.Limit(limit, start...)
session.Statement.Limit(limit, start...)
return session
}
func (session *Session) OrderBy(order string) *Session {
statement := session.AutoStatement()
statement.OrderBy(order)
session.Statement.OrderBy(order)
return session
}
//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (session *Session) Join(join_operator, tablename, condition string) *Session {
statement := session.AutoStatement()
statement.Join(join_operator, tablename, condition)
session.Statement.Join(join_operator, tablename, condition)
return session
}
func (session *Session) GroupBy(keys string) *Session {
statement := session.AutoStatement()
statement.GroupBy(keys)
session.Statement.GroupBy(keys)
return session
}
func (session *Session) Having(conditions string) *Session {
statement := session.AutoStatement()
statement.Having(conditions)
session.Statement.Having(conditions)
return session
}
func (session *Session) Begin() error {
session.IsAutoCommit = false
session.IsAutoRollback = true
tx, err := session.Db.Begin()
session.Tx = tx
if session.Engine.ShowSQL {
fmt.Println("BEGIN TRANSACTION")
}
return err
}
func (session *Session) Rollback() error {
if session.Engine.ShowSQL {
fmt.Println("ROLL BACK")
}
return session.Tx.Rollback()
}
func (session *Session) Commit() error {
if session.Engine.ShowSQL {
fmt.Println("COMMIT")
}
return session.Tx.Commit()
}
@ -133,27 +111,10 @@ func (session *Session) TableName(bean interface{}) string {
return session.Mapper.Obj2Table(StructName(bean))
}
func (session *Session) SetStatement(statement *Statement) {
if session.CurStatementIdx == len(session.Statements)-1 {
session.Statements = append(session.Statements, *statement)
} else {
session.Statements[session.CurStatementIdx+1] = *statement
}
session.CurStatementIdx = session.CurStatementIdx + 1
}
func (session *Session) newStatement() {
if session.CurStatementIdx == len(session.Statements)-1 {
state := Statement{Session: session}
state.Init()
session.Statements = append(session.Statements, state)
}
session.CurStatementIdx = session.CurStatementIdx + 1
}
func (session *Session) clearStatment() {
session.Statements[session.CurStatementIdx].Init()
session.CurStatementIdx = session.CurStatementIdx - 1
func (session *Session) Bean2Table(bean interface{}) *Table {
tablName := session.TableName(bean)
table := session.Engine.Tables[tablName]
return &table
}
func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error {
@ -162,8 +123,7 @@ func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]b
return errors.New("expected a pointer to a struct")
}
tablName := session.TableName(obj)
table := session.Engine.Tables[tablName]
table := session.Bean2Table(obj)
for key, data := range objMap {
structField := dataStruct.FieldByName(table.Columns[key].FieldName)
@ -231,8 +191,8 @@ func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]b
}
//Execute sql
func (session *Session) Exec(finalQueryString string, args ...interface{}) (sql.Result, error) {
rs, err := session.Db.Prepare(finalQueryString)
func (session *Session) innerExec(sql string, args ...interface{}) (sql.Result, error) {
rs, err := session.Db.Prepare(sql)
if err != nil {
return nil, err
}
@ -245,18 +205,30 @@ func (session *Session) Exec(finalQueryString string, args ...interface{}) (sql.
return res, nil
}
func (session *Session) Get(bean interface{}) error {
statement := session.AutoStatement()
statement.Limit(1)
tableName := session.TableName(bean)
table := session.Engine.Tables[tableName]
statement.Table = &table
func (session *Session) Exec(sql string, args ...interface{}) (sql.Result, error) {
if session.Engine.ShowSQL {
fmt.Println(sql)
}
if session.IsAutoCommit {
return session.innerExec(sql, args...)
}
return session.Tx.Exec(sql, args...)
}
colNames, args := session.BuildConditions(&table, bean)
func (session *Session) Get(bean interface{}) error {
statement := session.Statement
defer session.Statement.Init()
statement.Limit(1)
table := session.Bean2Table(bean)
statement.Table = table
colNames, args := session.BuildConditions(table, bean)
statement.ColumnStr = strings.Join(colNames, " and ")
statement.BeanArgs = args
resultsSlice, err := session.FindMap(statement)
sql := statement.generateSql()
resultsSlice, err := session.Query(sql, append(statement.Params, statement.BeanArgs...)...)
if err != nil {
return err
}
@ -275,16 +247,16 @@ func (session *Session) Get(bean interface{}) error {
}
func (session *Session) Count(bean interface{}) (int64, error) {
statement := session.AutoStatement()
tableName := session.TableName(bean)
table := session.Engine.Tables[tableName]
statement.Table = &table
statement := session.Statement
defer session.Statement.Init()
table := session.Bean2Table(bean)
statement.Table = table
colNames, args := session.BuildConditions(&table, bean)
colNames, args := session.BuildConditions(table, bean)
statement.ColumnStr = strings.Join(colNames, " and ")
statement.BeanArgs = args
resultsSlice, err := session.SQL2Map(statement.genCountSql(), append(statement.Params, statement.BeanArgs...))
resultsSlice, err := session.Query(statement.genCountSql(), append(statement.Params, statement.BeanArgs...)...)
if err != nil {
return 0, err
}
@ -298,9 +270,9 @@ func (session *Session) Count(bean interface{}) (int64, error) {
return int64(total), err
}
func (session *Session) Find(rowsSlicePtr interface{}) error {
statement := session.AutoStatement()
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
statement := session.Statement
defer session.Statement.Init()
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice {
return errors.New("needs a pointer to a slice")
@ -312,7 +284,15 @@ func (session *Session) Find(rowsSlicePtr interface{}) error {
table := session.Engine.Tables[tableName]
statement.Table = &table
resultsSlice, err := session.FindMap(statement)
if len(condiBean) > 0 {
colNames, args := session.BuildConditions(&table, condiBean[0])
statement.ColumnStr = strings.Join(colNames, " and ")
statement.BeanArgs = args
}
sql := statement.generateSql()
resultsSlice, err := session.Query(sql, append(statement.Params, statement.BeanArgs...)...)
if err != nil {
return err
}
@ -328,7 +308,7 @@ func (session *Session) Find(rowsSlicePtr interface{}) error {
return nil
}
func (session *Session) SQL2Map(sqls string, paramStr []interface{}) (resultsSlice []map[string][]byte, err error) {
func (session *Session) Query(sqls string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
if session.Engine.ShowSQL {
fmt.Println(sqls)
}
@ -397,11 +377,6 @@ func (session *Session) SQL2Map(sqls string, paramStr []interface{}) (resultsSli
return resultsSlice, nil
}
func (session *Session) FindMap(statement *Statement) (resultsSlice []map[string][]byte, err error) {
sqls := statement.generateSql()
return session.SQL2Map(sqls, append(statement.Params, statement.BeanArgs...))
}
func (session *Session) Insert(beans ...interface{}) (int64, error) {
var lastId int64 = -1
for _, bean := range beans {
@ -414,8 +389,7 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
}
func (session *Session) InsertOne(bean interface{}) (int64, error) {
tableName := session.TableName(bean)
table := session.Engine.Tables[tableName]
table := session.Bean2Table(bean)
colNames := make([]string, 0)
colPlaces := make([]string, 0)
@ -423,11 +397,9 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
for _, col := range table.Columns {
fieldValue := reflect.Indirect(reflect.ValueOf(bean)).FieldByName(col.FieldName)
val := fieldValue.Interface()
if col.IsAutoIncrement {
if fieldValue.Int() == 0 {
if col.IsAutoIncrement && fieldValue.Int() == 0 {
continue
}
}
args = append(args, val)
colNames = append(colNames, col.Name)
colPlaces = append(colPlaces, "?")
@ -435,23 +407,12 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
statement := fmt.Sprintf("INSERT INTO %v%v%v (%v) VALUES (%v)",
session.Engine.QuoteIdentifier,
tableName,
table.Name,
session.Engine.QuoteIdentifier,
strings.Join(colNames, ", "),
strings.Join(colPlaces, ", "))
if session.Engine.ShowSQL {
fmt.Println(statement)
}
var res sql.Result
var err error
if session.IsAutoCommit {
res, err = session.Exec(statement, args...)
} else {
res, err = session.Tx.Exec(statement, args...)
}
res, err := session.Exec(statement, args...)
if err != nil {
return -1, err
}
@ -461,6 +422,7 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
if err != nil {
return -1, err
}
return id, nil
}
@ -497,46 +459,42 @@ func (session *Session) BuildConditions(table *Table, bean interface{}) ([]strin
return colNames, args
}
func (session *Session) Update(bean interface{}) (int64, error) {
tableName := session.TableName(bean)
table := session.Engine.Tables[tableName]
colNames, args := session.BuildConditions(&table, bean)
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
table := session.Bean2Table(bean)
colNames, args := session.BuildConditions(table, bean)
var condiColNames []string
var condiArgs []interface{}
if len(condiBean) > 0 {
condiColNames, condiArgs = session.BuildConditions(table, condiBean[0])
}
var condition = ""
st := session.AutoStatement()
defer session.clearStatment()
st := session.Statement
defer session.Statement.Init()
if st.WhereStr != "" {
condition = fmt.Sprintf("WHERE %v", st.WhereStr)
}
if condition == "" {
fieldValue := reflect.Indirect(reflect.ValueOf(bean)).FieldByName(table.PKColumn().FieldName)
if fieldValue.Int() != 0 {
condition = fmt.Sprintf("WHERE %v = ?", table.PKColumn().Name)
args = append(args, fieldValue.Interface())
if len(condiColNames) > 0 {
condition = fmt.Sprintf("WHERE %v ", strings.Join(condiColNames, " and "))
}
} else {
if len(condiColNames) > 0 {
condition = fmt.Sprintf("%v and %v", condition, strings.Join(condiColNames, " and "))
}
}
statement := fmt.Sprintf("UPDATE %v%v%v SET %v %v",
session.Engine.QuoteIdentifier,
tableName,
table.Name,
session.Engine.QuoteIdentifier,
strings.Join(colNames, ", "),
condition)
if session.Engine.ShowSQL {
fmt.Println(statement)
}
var res sql.Result
var err error
if session.IsAutoCommit {
fmt.Println("session.Exec")
res, err = session.Exec(statement, append(args, st.Params...)...)
} else {
fmt.Println("tx.Exec")
res, err = session.Tx.Exec(statement, append(args, st.Params...)...)
}
eargs := append(append(args, st.Params...), condiArgs...)
res, err := session.Exec(statement, eargs...)
if err != nil {
return -1, err
}
@ -550,13 +508,12 @@ func (session *Session) Update(bean interface{}) (int64, error) {
}
func (session *Session) Delete(bean interface{}) (int64, error) {
tableName := session.TableName(bean)
table := session.Engine.Tables[tableName]
colNames, args := session.BuildConditions(&table, bean)
table := session.Bean2Table(bean)
colNames, args := session.BuildConditions(table, bean)
var condition = ""
st := session.AutoStatement()
defer session.clearStatment()
st := session.Statement
defer session.Statement.Init()
if st.WhereStr != "" {
condition = fmt.Sprintf("WHERE %v", st.WhereStr)
if len(colNames) > 0 {
@ -569,21 +526,12 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
statement := fmt.Sprintf("DELETE FROM %v%v%v %v",
session.Engine.QuoteIdentifier,
tableName,
table.Name,
session.Engine.QuoteIdentifier,
condition)
if session.Engine.ShowSQL {
fmt.Println(statement)
}
res, err := session.Exec(statement, append(st.Params, args...)...)
var res sql.Result
var err error
if session.IsAutoCommit {
res, err = session.Exec(statement, append(st.Params, args...)...)
} else {
res, err = session.Tx.Exec(statement, append(st.Params, args...)...)
}
if err != nil {
return -1, err
}

View File

@ -6,7 +6,7 @@ import (
type Statement struct {
Table *Table
Session *Session
Engine *Engine
Start int
LimitN int
WhereStr string
@ -21,7 +21,6 @@ type Statement struct {
func (statement *Statement) Init() {
statement.Table = nil
statement.Session = nil
statement.Start = 0
statement.LimitN = 0
statement.WhereStr = ""
@ -76,13 +75,8 @@ func (statement Statement) genCountSql() string {
return statement.genSelectSql("count(*) as total")
}
func (statement Statement) genExecSql() string {
return ""
}
func (statement Statement) genSelectSql(columnStr string) (a string) {
session := statement.Session
if session.Engine.Protocol == "mssql" {
if statement.Engine.Protocol == "mssql" {
if statement.Start > 0 {
a = fmt.Sprintf("select ROW_NUMBER() OVER(order by %v )as rownum,%v from %v",
statement.Table.PKColumn().Name,
@ -171,24 +165,3 @@ func (statement Statement) genSelectSql(columnStr string) (a string) {
}
return
}
/*func (statement *Statement) genInsertSQL() string {
table = statement.Table
colNames := make([]string, len(table.Columns))
for idx, col := range table.Columns {
if col.Name == "" {
continue
}
colNames[idx] = col.Name
}
return strings.Join(colNames, ", ")
colNames := make([]string, len(table.Columns))
for idx, col := range table.Columns {
if col.Name == "" {
continue
}
colNames[idx] = "?"
}
strings.Join(colNames, ", ")
}*/

View File

@ -72,7 +72,7 @@ type Table struct {
func (table *Table) ColumnStr() string {
colNames := make([]string, 0)
for _, col := range table.Columns {
colNames = append(colNames, col.Name)
colNames = append(colNames, table.Name+"."+col.Name)
}
return strings.Join(colNames, ", ")
}

View File

@ -12,6 +12,7 @@ func Create(schema string) Engine {
engine := Engine{}
engine.Mapper = SnakeMapper{}
engine.Tables = make(map[string]Table)
engine.Statement.Engine = &engine
l := strings.Split(schema, "://")
if len(l) == 2 {
engine.Protocol = l[0]

View File

@ -33,6 +33,12 @@ type Userinfo struct {
Created time.Time
}
type Userdetail struct {
Uid int `xorm:"id pk not null"`
Intro string
Profile string
}
var engine xorm.Engine
func directCreateTable(t *testing.T) {
@ -48,7 +54,7 @@ func mapper(t *testing.T) {
t.Error(err)
}
err = engine.Map(&Userinfo{})
err = engine.Map(&Userinfo{}, &Userdetail{})
if err != nil {
t.Error(err)
}
@ -72,6 +78,24 @@ func insert(t *testing.T) {
}
}
func query(t *testing.T) {
sql := "select * from userinfo"
results, err := engine.Query(sql)
if err != nil {
t.Error(err)
}
fmt.Println(results)
}
func exec(t *testing.T) {
sql := "update userinfo set username=? where id=?"
res, err := engine.Exec(sql, "xiaolun", 1)
if err != nil {
t.Error(err)
}
fmt.Println(res)
}
func insertAutoIncr(t *testing.T) {
// auto increment insert
user := Userinfo{Username: "xiaolunwen", Departname: "dev", Alias: "lunny", Created: time.Now()}
@ -90,10 +114,26 @@ func insertMulti(t *testing.T) {
}
}
func insertTwoTable(t *testing.T) {
userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now()}
uid, err := engine.Insert(&userinfo)
if err != nil {
t.Error(err)
return
}
userdetail := Userdetail{Uid: int(uid), Intro: "I'm a very beautiful women.", Profile: "sfsaf"}
_, err = engine.Insert(&userdetail)
if err != nil {
t.Error(err)
}
}
func update(t *testing.T) {
// update by id
user := Userinfo{Uid: 1, Username: "xxx"}
_, err := engine.Update(&user)
user := Userinfo{Username: "xxx"}
condiUser := Userinfo{Uid: 1}
_, err := engine.Update(&user, &condiUser)
if err != nil {
t.Error(err)
}
@ -163,6 +203,23 @@ func order(t *testing.T) {
fmt.Println(users)
}
func join(t *testing.T) {
users := make([]Userinfo, 0)
err := engine.Join("LEFT", "userdetail", "userinfo.id=userdetail.id").Find(&users)
if err != nil {
t.Error(err)
}
}
func having(t *testing.T) {
users := make([]Userinfo, 0)
err := engine.GroupBy("username").Having("username='xlw'").Find(&users)
if err != nil {
t.Error(err)
}
fmt.Println(users)
}
func transaction(t *testing.T) {
counter := func() {
total, err := engine.Count(&Userinfo{})
@ -173,7 +230,7 @@ func transaction(t *testing.T) {
}
counter()
defer counter()
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
@ -181,25 +238,76 @@ func transaction(t *testing.T) {
return
}
defer counter()
session.Begin()
session.IsAutoRollback = true
//session.IsAutoRollback = false
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
t.Error(err)
return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
_, err = session.Where("uid = ?", 0).Update(&user2)
if err != nil {
t.Error(err)
session.Rollback()
fmt.Println(err)
//t.Error(err)
return
}
_, err = session.Delete(&user2)
if err != nil {
session.Rollback()
t.Error(err)
return
}
err = session.Commit()
if err != nil {
t.Error(err)
return
}
}
func combineTransaction(t *testing.T) {
counter := func() {
total, err := engine.Count(&Userinfo{})
if err != nil {
t.Error(err)
}
fmt.Printf("----now total %v records\n", total)
}
counter()
defer counter()
session, err := engine.MakeSession()
defer session.Close()
if err != nil {
t.Error(err)
return
}
session.Begin()
//session.IsAutoRollback = false
user1 := Userinfo{Username: "xiaoxiao2", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
t.Error(err)
return
}
user2 := Userinfo{Username: "zzz"}
_, err = session.Where("id = ?", 0).Update(&user2)
if err != nil {
session.Rollback()
t.Error(err)
return
}
_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
if err != nil {
session.Rollback()
t.Error(err)
return
}
@ -218,6 +326,8 @@ func TestMysql(t *testing.T) {
directCreateTable(t)
mapper(t)
insert(t)
query(t)
exec(t)
insertAutoIncr(t)
insertMulti(t)
update(t)
@ -228,7 +338,10 @@ func TestMysql(t *testing.T) {
where(t)
limit(t)
order(t)
join(t)
having(t)
transaction(t)
combineTransaction(t)
}
func TestSqlite(t *testing.T) {
@ -238,6 +351,8 @@ func TestSqlite(t *testing.T) {
directCreateTable(t)
mapper(t)
insert(t)
query(t)
exec(t)
insertAutoIncr(t)
insertMulti(t)
update(t)
@ -248,5 +363,8 @@ func TestSqlite(t *testing.T) {
where(t)
limit(t)
order(t)
join(t)
having(t)
transaction(t)
combineTransaction(t)
}