Skip to content

Commit

Permalink
add QueryExpr function
Browse files Browse the repository at this point in the history
  • Loading branch information
xormplus committed Dec 5, 2018
1 parent 4fd8a98 commit dd83e8e
Show file tree
Hide file tree
Showing 17 changed files with 293 additions and 18 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,14 @@ err := engine.Table("user").Select("user.*, detail.*")
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
```

* 子查询

```Go
var student []Student
err = db.Table("student").Select("id ,name").Where("id in (?)", db.Table("studentinfo").Select("id").Where("status = ?", 2).QueryExpr()).Find(&student)
//SELECT id ,name FROM `student` WHERE (id in (SELECT id FROM `studentinfo` WHERE (status = 2)))
```

* 根据条件遍历数据库,可以有两种方式: Iterate and Rows

```Go
Expand Down
2 changes: 1 addition & 1 deletion engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"time"

"github.com/fsnotify/fsnotify"
"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
2 changes: 1 addition & 1 deletion engine_cond.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"strings"
"time"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
2 changes: 2 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ var (
ErrNotImplemented = errors.New("Not implemented")
// ErrConditionType condition type unsupported
ErrConditionType = errors.New("Unsupported condition type")
// ErrNeedMoreArguments need more arguments
ErrNeedMoreArguments = errors.New("Need more sql arguments")
)

// ErrFieldIsNotExist columns does not exist
Expand Down
2 changes: 1 addition & 1 deletion session_cond.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

package xorm

import "github.com/go-xorm/builder"
import "github.com/xormplus/builder"

// Sql provides raw sql input parameter. When you have a complex SQL statement
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
Expand Down
2 changes: 1 addition & 1 deletion session_cond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"fmt"
"testing"

"github.com/go-xorm/builder"
"github.com/stretchr/testify/assert"
"github.com/xormplus/builder"
)

func TestBuilder(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion session_exist.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"fmt"
"reflect"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
2 changes: 1 addition & 1 deletion session_find.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"reflect"
"strings"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
23 changes: 22 additions & 1 deletion session_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"strings"
"time"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down Expand Up @@ -384,3 +384,24 @@ func (session *Session) QueryInterface(sqlorArgs ...interface{}) ([]map[string]i

return rows2Interfaces(rows)
}

// QueryExpr returns the query as bound SQL
func (session *Session) QueryExpr(sqlorArgs ...interface{}) sqlExpr {
if session.isAutoClose {
defer session.Close()
}

sqlStr, args, err := session.genQuerySQL()
if err != nil {
session.engine.logger.Error(err)
return sqlExpr{sqlExpr: ""}
}

sqlStr, err = ConvertToBoundSQL(sqlStr, args)
if err != nil {
session.engine.logger.Error(err)
return sqlExpr{sqlExpr: ""}
}

return sqlExpr{sqlExpr: sqlStr}
}
4 changes: 2 additions & 2 deletions session_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"testing"
"time"

"github.com/go-xorm/builder"
"github.com/go-xorm/core"
"github.com/xormplus/builder"
"github.com/xormplus/core"

"github.com/stretchr/testify/assert"
)
Expand Down
2 changes: 1 addition & 1 deletion session_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"reflect"
"time"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
2 changes: 1 addition & 1 deletion session_stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"strconv"
"testing"

"github.com/go-xorm/builder"
"github.com/stretchr/testify/assert"
"github.com/xormplus/builder"
)

func isFloatEq(i, j float64, precision int) bool {
Expand Down
2 changes: 1 addition & 1 deletion session_sum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"strconv"
"testing"

"github.com/go-xorm/builder"
"github.com/stretchr/testify/assert"
"github.com/xormplus/builder"
)

func isFloatEq(i, j float64, precision int) bool {
Expand Down
2 changes: 1 addition & 1 deletion session_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"strconv"
"strings"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down
96 changes: 96 additions & 0 deletions sql_expr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package xorm

import (
sql2 "database/sql"
"fmt"
"reflect"
"time"
)

type sqlExpr struct {
sqlExpr string
}

func noSQLQuoteNeeded(a interface{}) bool {
switch a.(type) {
case int, int8, int16, int32, int64:
return true
case uint, uint8, uint16, uint32, uint64:
return true
case float32, float64:
return true
case bool:
return true
case string:
return false
case time.Time, *time.Time:
return false
case sqlExpr, *sqlExpr:
return true
}

t := reflect.TypeOf(a)
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.Bool:
return true
case reflect.String:
return false
}

return false
}

// ConvertToBoundSQL will convert SQL and args to a bound SQL
func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
buf := StringBuilder{}
var i, j, start int
for ; i < len(sql); i++ {
if sql[i] == '?' {
_, err := buf.WriteString(sql[start:i])
if err != nil {
return "", err
}
start = i + 1

if len(args) == j {
return "", ErrNeedMoreArguments
}

arg := args[j]

if exprArg, ok := arg.(sqlExpr); ok {
_, err = fmt.Fprint(&buf, exprArg.sqlExpr)
if err != nil {
return "", err
}

} else {
if namedArg, ok := arg.(sql2.NamedArg); ok {
arg = namedArg.Value
}

if noSQLQuoteNeeded(arg) {
_, err = fmt.Fprint(&buf, arg)
} else {
_, err = fmt.Fprintf(&buf, "'%v'", arg)
}
if err != nil {
return "", err
}
}

j = j + 1
}
}
_, err := buf.WriteString(sql[start:])
if err != nil {
return "", err
}
return buf.String(), nil
}
39 changes: 34 additions & 5 deletions statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"strings"
"time"

"github.com/go-xorm/builder"
"github.com/xormplus/builder"
"github.com/xormplus/core"
)

Expand Down Expand Up @@ -146,8 +146,22 @@ func (statement *Statement) Where(query interface{}, args ...interface{}) *State
func (statement *Statement) And(query interface{}, args ...interface{}) *Statement {
switch query.(type) {
case string:
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.And(cond)
isExpr := false
var cargs []interface{}
for i, _ := range args {
if _, ok := args[i].(sqlExpr); ok {
isExpr = true
}
cargs = append(cargs, args[i])
}
if isExpr {
sqlStr, _ := ConvertToBoundSQL(query.(string), cargs)
cond := builder.Expr(sqlStr)
statement.cond = statement.cond.And(cond)
} else {
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.And(cond)
}
case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.And(cond)
Expand All @@ -170,8 +184,23 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme
func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement {
switch query.(type) {
case string:
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.Or(cond)
isExpr := false
var cargs []interface{}
for i, _ := range args {
if _, ok := args[i].(sqlExpr); ok {
isExpr = true
}
cargs = append(cargs, args[i])
}
if isExpr {
sqlStr, _ := ConvertToBoundSQL(query.(string), cargs)
cond := builder.Expr(sqlStr)
statement.cond = statement.cond.Or(cond)
} else {
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.Or(cond)
}

case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.Or(cond)
Expand Down
Loading

0 comments on commit dd83e8e

Please sign in to comment.