fix: 从xorm.io变更为gitea.com/laixyz,并合并了builder目录
This commit is contained in:
parent
f10e21cb15
commit
e9b1fcf3dd
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2016 The Xorm Authors
|
||||
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.
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
# SQL builder
|
||||
|
||||
[](https://drone.gitea.com/xorm/builder) [](http://gocover.io/xorm.io/builder)
|
||||
[](https://goreportcard.com/report/xorm.io/builder)
|
||||
|
||||
Package builder is a lightweight and fast SQL builder for Go and XORM.
|
||||
|
||||
Make sure you have installed Go 1.8+ and then:
|
||||
|
||||
go get xorm.io/builder
|
||||
|
||||
# Insert
|
||||
|
||||
```Go
|
||||
sql, args, err := builder.Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
|
||||
|
||||
// INSERT INTO table1 SELECT * FROM table2
|
||||
sql, err := builder.Insert().Into("table1").Select().From("table2").ToBoundSQL()
|
||||
|
||||
// INSERT INTO table1 (a, b) SELECT b, c FROM table2
|
||||
sql, err = builder.Insert("a, b").Into("table1").Select("b, c").From("table2").ToBoundSQL()
|
||||
```
|
||||
|
||||
# Select
|
||||
|
||||
```Go
|
||||
// Simple Query
|
||||
sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
// With join
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
// From sub query
|
||||
sql, args, err := Select("sub.id").From(Select("c").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
// From union query
|
||||
sql, args, err = Select("sub.id").From(
|
||||
Select("id").From("table1").Where(Eq{"a": 1}).Union("all", Select("id").From("table1").Where(Eq{"a": 2})),"sub").
|
||||
Where(Eq{"b": 1}).ToSQL()
|
||||
// With order by
|
||||
sql, args, err = Select("a", "b", "c").From("table1").Where(Eq{"f1": "v1", "f2": "v2"}).
|
||||
OrderBy("a ASC").ToSQL()
|
||||
// With limit.
|
||||
// Be careful! You should set up specific dialect for builder before performing a query with LIMIT
|
||||
sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
|
||||
Limit(5, 10).ToSQL()
|
||||
```
|
||||
|
||||
# Update
|
||||
|
||||
```Go
|
||||
sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
```
|
||||
|
||||
# Delete
|
||||
|
||||
```Go
|
||||
sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
|
||||
```
|
||||
|
||||
# Union
|
||||
|
||||
```Go
|
||||
sql, args, err := Select("*").From("a").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("a").Where(Eq{"status": "2"})).
|
||||
Union("distinct", Select("*").From("a").Where(Eq{"status": "3"})).
|
||||
Union("", Select("*").From("a").Where(Eq{"status": "4"})).
|
||||
ToSQL()
|
||||
```
|
||||
|
||||
# Conditions
|
||||
|
||||
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Eq{"a":1})
|
||||
// a=? [1]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
|
||||
// b=? AND c=? ["c", 0]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
|
||||
// b=? AND c=? ["c", 0]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
|
||||
// b=? OR b=? ["c", "d"]
|
||||
sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
|
||||
// b IN (?,?) ["c", "d"]
|
||||
sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
|
||||
// b=? AND c IN (?,?) [1, 2, 3]
|
||||
```
|
||||
|
||||
* `Neq` is the same to `Eq`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Neq{"a":1})
|
||||
// a<>? [1]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
|
||||
// b<>? AND c<>? ["c", 0]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
|
||||
// b<>? AND c<>? ["c", 0]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
|
||||
// b<>? OR b<>? ["c", "d"]
|
||||
sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
|
||||
// b NOT IN (?,?) ["c", "d"]
|
||||
sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
|
||||
// b<>? AND c NOT IN (?,?) [1, 2, 3]
|
||||
```
|
||||
|
||||
* `Gt`, `Gte`, `Lt`, `Lte`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
||||
// a>? AND b>=? [1, 2]
|
||||
sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
|
||||
// a<? OR b<=? [1, 2]
|
||||
```
|
||||
|
||||
* `Like`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Like{"a", "c"})
|
||||
// a LIKE ? [%c%]
|
||||
```
|
||||
|
||||
* `Expr` you can customerize your sql with `Expr`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
||||
// a = ? [1]
|
||||
sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
|
||||
// a=(select id from table where c = ?) [1]
|
||||
```
|
||||
|
||||
* `In` and `NotIn`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
||||
// a IN (?,?,?) [1,2,3]
|
||||
sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
|
||||
// a IN (?,?,?) [1,2,3]
|
||||
sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
|
||||
// a IN (select id from b where c = ?) [1]
|
||||
```
|
||||
|
||||
* `IsNull` and `NotNull`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(IsNull{"a"})
|
||||
// a IS NULL []
|
||||
sql, args, _ := ToSQL(NotNull{"b"})
|
||||
// b IS NOT NULL []
|
||||
```
|
||||
|
||||
* `And(conds ...Cond)`, And can connect one or more condtions via And
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
||||
```
|
||||
|
||||
* `Or(conds ...Cond)`, Or can connect one or more conditions via Or
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
|
||||
// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
|
||||
```
|
||||
|
||||
* `Between`
|
||||
|
||||
```Go
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Between{"a", 1, 2})
|
||||
// a BETWEEN 1 AND 2
|
||||
```
|
||||
|
||||
* Define yourself conditions
|
||||
|
||||
Since `Cond` is an interface.
|
||||
|
||||
```Go
|
||||
type Cond interface {
|
||||
WriteTo(Writer) error
|
||||
And(...Cond) Cond
|
||||
Or(...Cond) Cond
|
||||
IsValid() bool
|
||||
}
|
||||
```
|
||||
|
||||
You can define yourself conditions and compose with other `Cond`.
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
sql2 "database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type optype byte
|
||||
|
||||
const (
|
||||
condType optype = iota // only conditions
|
||||
selectType // select
|
||||
insertType // insert
|
||||
updateType // update
|
||||
deleteType // delete
|
||||
setOpType // set operation
|
||||
)
|
||||
|
||||
// all databasees
|
||||
const (
|
||||
POSTGRES = "postgres"
|
||||
SQLITE = "sqlite3"
|
||||
MYSQL = "mysql"
|
||||
MSSQL = "mssql"
|
||||
ORACLE = "oracle"
|
||||
|
||||
UNION = "union"
|
||||
INTERSECT = "intersect"
|
||||
EXCEPT = "except"
|
||||
)
|
||||
|
||||
type join struct {
|
||||
joinType string
|
||||
joinTable interface{}
|
||||
joinCond Cond
|
||||
}
|
||||
|
||||
type setOp struct {
|
||||
opType string
|
||||
distinctType string
|
||||
builder *Builder
|
||||
}
|
||||
|
||||
type limit struct {
|
||||
limitN int
|
||||
offset int
|
||||
}
|
||||
|
||||
// Builder describes a SQL statement
|
||||
type Builder struct {
|
||||
optype
|
||||
dialect string
|
||||
isNested bool
|
||||
into string
|
||||
from string
|
||||
subQuery *Builder
|
||||
cond Cond
|
||||
selects []string
|
||||
joins []join
|
||||
setOps []setOp
|
||||
limitation *limit
|
||||
insertCols []string
|
||||
insertVals []interface{}
|
||||
updates []UpdateCond
|
||||
orderBy string
|
||||
groupBy string
|
||||
having string
|
||||
}
|
||||
|
||||
// Dialect sets the db dialect of Builder.
|
||||
func Dialect(dialect string) *Builder {
|
||||
builder := &Builder{cond: NewCond(), dialect: dialect}
|
||||
return builder
|
||||
}
|
||||
|
||||
// MySQL is shortcut of Dialect(MySQL)
|
||||
func MySQL() *Builder {
|
||||
return Dialect(MYSQL)
|
||||
}
|
||||
|
||||
// MsSQL is shortcut of Dialect(MsSQL)
|
||||
func MsSQL() *Builder {
|
||||
return Dialect(MSSQL)
|
||||
}
|
||||
|
||||
// Oracle is shortcut of Dialect(Oracle)
|
||||
func Oracle() *Builder {
|
||||
return Dialect(ORACLE)
|
||||
}
|
||||
|
||||
// Postgres is shortcut of Dialect(Postgres)
|
||||
func Postgres() *Builder {
|
||||
return Dialect(POSTGRES)
|
||||
}
|
||||
|
||||
// SQLite is shortcut of Dialect(SQLITE)
|
||||
func SQLite() *Builder {
|
||||
return Dialect(SQLITE)
|
||||
}
|
||||
|
||||
// Where sets where SQL
|
||||
func (b *Builder) Where(cond Cond) *Builder {
|
||||
if b.cond.IsValid() {
|
||||
b.cond = b.cond.And(cond)
|
||||
} else {
|
||||
b.cond = cond
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// From sets from subject(can be a table name in string or a builder pointer) and its alias
|
||||
func (b *Builder) From(subject interface{}, alias ...string) *Builder {
|
||||
switch subject.(type) {
|
||||
case *Builder:
|
||||
b.subQuery = subject.(*Builder)
|
||||
|
||||
if len(alias) > 0 {
|
||||
b.from = alias[0]
|
||||
} else {
|
||||
b.isNested = true
|
||||
}
|
||||
case string:
|
||||
b.from = subject.(string)
|
||||
|
||||
if len(alias) > 0 {
|
||||
b.from = b.from + " " + alias[0]
|
||||
}
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// TableName returns the table name
|
||||
func (b *Builder) TableName() string {
|
||||
if b.optype == insertType {
|
||||
return b.into
|
||||
}
|
||||
return b.from
|
||||
}
|
||||
|
||||
// Into sets insert table name
|
||||
func (b *Builder) Into(tableName string) *Builder {
|
||||
b.into = tableName
|
||||
return b
|
||||
}
|
||||
|
||||
// Union sets union conditions
|
||||
func (b *Builder) Union(distinctType string, cond *Builder) *Builder {
|
||||
return b.setOperation(UNION, distinctType, cond)
|
||||
}
|
||||
|
||||
// Intersect sets intersect conditions
|
||||
func (b *Builder) Intersect(distinctType string, cond *Builder) *Builder {
|
||||
return b.setOperation(INTERSECT, distinctType, cond)
|
||||
}
|
||||
|
||||
// Except sets except conditions
|
||||
func (b *Builder) Except(distinctType string, cond *Builder) *Builder {
|
||||
return b.setOperation(EXCEPT, distinctType, cond)
|
||||
}
|
||||
|
||||
func (b *Builder) setOperation(opType, distinctType string, cond *Builder) *Builder {
|
||||
|
||||
var builder *Builder
|
||||
if b.optype != setOpType {
|
||||
builder = &Builder{cond: NewCond()}
|
||||
builder.optype = setOpType
|
||||
builder.dialect = b.dialect
|
||||
builder.selects = b.selects
|
||||
|
||||
currentSetOps := b.setOps
|
||||
// erase sub setOps (actually append to new Builder.unions)
|
||||
b.setOps = nil
|
||||
|
||||
for e := range currentSetOps {
|
||||
currentSetOps[e].builder.dialect = b.dialect
|
||||
}
|
||||
|
||||
builder.setOps = append(append(builder.setOps, setOp{opType, "", b}), currentSetOps...)
|
||||
} else {
|
||||
builder = b
|
||||
}
|
||||
|
||||
if cond != nil {
|
||||
if cond.dialect == "" && builder.dialect != "" {
|
||||
cond.dialect = builder.dialect
|
||||
}
|
||||
|
||||
builder.setOps = append(builder.setOps, setOp{opType, distinctType, cond})
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Limit sets limitN condition
|
||||
func (b *Builder) Limit(limitN int, offset ...int) *Builder {
|
||||
b.limitation = &limit{limitN: limitN}
|
||||
|
||||
if len(offset) > 0 {
|
||||
b.limitation.offset = offset[0]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Select sets select SQL
|
||||
func (b *Builder) Select(cols ...string) *Builder {
|
||||
b.selects = cols
|
||||
if b.optype == condType {
|
||||
b.optype = selectType
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// And sets AND condition
|
||||
func (b *Builder) And(cond Cond) *Builder {
|
||||
b.cond = And(b.cond, cond)
|
||||
return b
|
||||
}
|
||||
|
||||
// Or sets OR condition
|
||||
func (b *Builder) Or(cond Cond) *Builder {
|
||||
b.cond = Or(b.cond, cond)
|
||||
return b
|
||||
}
|
||||
|
||||
// Update sets update SQL
|
||||
func (b *Builder) Update(updates ...Cond) *Builder {
|
||||
b.updates = make([]UpdateCond, 0, len(updates))
|
||||
for _, update := range updates {
|
||||
if u, ok := update.(UpdateCond); ok && u.IsValid() {
|
||||
b.updates = append(b.updates, u)
|
||||
}
|
||||
}
|
||||
b.optype = updateType
|
||||
return b
|
||||
}
|
||||
|
||||
// Delete sets delete SQL
|
||||
func (b *Builder) Delete(conds ...Cond) *Builder {
|
||||
b.cond = b.cond.And(conds...)
|
||||
b.optype = deleteType
|
||||
return b
|
||||
}
|
||||
|
||||
// WriteTo implements Writer interface
|
||||
func (b *Builder) WriteTo(w Writer) error {
|
||||
switch b.optype {
|
||||
/*case condType:
|
||||
return b.cond.WriteTo(w)*/
|
||||
case selectType:
|
||||
return b.selectWriteTo(w)
|
||||
case insertType:
|
||||
return b.insertWriteTo(w)
|
||||
case updateType:
|
||||
return b.updateWriteTo(w)
|
||||
case deleteType:
|
||||
return b.deleteWriteTo(w)
|
||||
case setOpType:
|
||||
return b.setOpWriteTo(w)
|
||||
}
|
||||
|
||||
return ErrNotSupportType
|
||||
}
|
||||
|
||||
// ToSQL convert a builder to SQL and args
|
||||
func (b *Builder) ToSQL() (string, []interface{}, error) {
|
||||
w := NewWriter()
|
||||
if err := b.WriteTo(w); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// in case of sql.NamedArg in args
|
||||
for e := range w.args {
|
||||
if namedArg, ok := w.args[e].(sql2.NamedArg); ok {
|
||||
w.args[e] = namedArg.Value
|
||||
}
|
||||
}
|
||||
|
||||
var sql = w.String()
|
||||
var err error
|
||||
|
||||
switch b.dialect {
|
||||
case ORACLE, MSSQL:
|
||||
// This is for compatibility with different sql drivers
|
||||
for e := range w.args {
|
||||
w.args[e] = sql2.Named(fmt.Sprintf("p%d", e+1), w.args[e])
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if b.dialect == ORACLE {
|
||||
prefix = ":p"
|
||||
} else {
|
||||
prefix = "@p"
|
||||
}
|
||||
|
||||
if sql, err = ConvertPlaceholder(sql, prefix); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
case POSTGRES:
|
||||
if sql, err = ConvertPlaceholder(sql, "$"); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sql, w.args, nil
|
||||
}
|
||||
|
||||
// ToBoundSQL generated a bound SQL string
|
||||
func (b *Builder) ToBoundSQL() (string, error) {
|
||||
w := NewWriter()
|
||||
if err := b.WriteTo(w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ConvertToBoundSQL(w.String(), w.args)
|
||||
}
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type randGenConf struct {
|
||||
allowCond bool
|
||||
allowJoin bool
|
||||
allowLimit bool
|
||||
allowUnion bool
|
||||
allowHaving bool
|
||||
allowGroupBy bool
|
||||
allowOrderBy bool
|
||||
allowSubQuery bool
|
||||
}
|
||||
|
||||
var expectedValues = []interface{}{
|
||||
"dangerous", "fun", "degree", "hospital", "horseshoe", "summit", "parallel", "height", "recommend", "invite",
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
var queryFields = []string{"f1", "f2", "f2", "f4", "f5", "f6", "f7", "f8", "f9"}
|
||||
|
||||
func BenchmarkSelect_Simple(b *testing.B) {
|
||||
rgc := randGenConf{allowCond: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery("", &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SubQuery(b *testing.B) {
|
||||
rgc := randGenConf{allowSubQuery: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery("", &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectConditional4Oracle(b *testing.B) {
|
||||
rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(ORACLE, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectConditional4Mssql(b *testing.B) {
|
||||
rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(MSSQL, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectConditional4MysqlLike(b *testing.B) {
|
||||
rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(MYSQL, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectConditional4Mixed(b *testing.B) {
|
||||
rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(randDialect(), &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectComplex4Oracle(b *testing.B) {
|
||||
rgc := randGenConf{
|
||||
allowLimit: true, allowCond: true,
|
||||
allowGroupBy: true, allowHaving: true,
|
||||
allowOrderBy: true, allowSubQuery: true,
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(ORACLE, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectComplex4Mssql(b *testing.B) {
|
||||
rgc := randGenConf{
|
||||
allowLimit: true, allowCond: true,
|
||||
allowGroupBy: true, allowHaving: true,
|
||||
allowOrderBy: true, allowSubQuery: true,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(MSSQL, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectComplex4MysqlLike(b *testing.B) {
|
||||
rgc := randGenConf{
|
||||
allowLimit: true, allowCond: true,
|
||||
allowGroupBy: true, allowHaving: true,
|
||||
allowOrderBy: true, allowSubQuery: true,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(MYSQL, &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelect_SelectComplex4MysqlMixed(b *testing.B) {
|
||||
rgc := randGenConf{
|
||||
allowLimit: true, allowCond: true,
|
||||
allowGroupBy: true, allowHaving: true,
|
||||
allowOrderBy: true, allowSubQuery: true,
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randQuery(randDialect(), &rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInsert(b *testing.B) {
|
||||
rgc := randGenConf{allowCond: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randInsertByCondition(&rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUpdate(b *testing.B) {
|
||||
rgc := randGenConf{allowCond: true}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
randUpdateByCondition(&rgc).ToSQL()
|
||||
}
|
||||
}
|
||||
|
||||
// randQuery Generate a basic query for benchmark test. But be careful it's not a executable SQL in real db.
|
||||
func randQuery(dialect string, rgc *randGenConf) *Builder {
|
||||
b := randSelectByCondition(dialect, rgc)
|
||||
isUnionized := rgc.allowUnion && rand.Intn(1000) >= 500
|
||||
if isUnionized {
|
||||
r := rand.Intn(3) + 1
|
||||
for i := r; i < r; i++ {
|
||||
b = b.Union("all", randSelectByCondition(dialect, rgc))
|
||||
}
|
||||
}
|
||||
|
||||
if isUnionized && rgc.allowLimit && rand.Intn(1000) >= 500 {
|
||||
b = randLimit(Dialect(dialect).Select().From(b, "t"))
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func randInsertByCondition(rgc *randGenConf) *Builder {
|
||||
fields := randSelects()
|
||||
|
||||
times := rand.Intn(10) + 1
|
||||
|
||||
eqs := Eq{}
|
||||
for i := 0; i < times; i++ {
|
||||
eqs[fields[rand.Intn(len(fields))]] = "expected"
|
||||
}
|
||||
|
||||
b := Insert(eqs).From("table1")
|
||||
|
||||
if rgc.allowCond && rand.Intn(1000) >= 500 {
|
||||
b = b.Where(randCond(b.selects, 3))
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func randUpdateByCondition(rgc *randGenConf) *Builder {
|
||||
fields := randSelects()
|
||||
|
||||
times := rand.Intn(10) + 1
|
||||
|
||||
eqs := Eq{}
|
||||
for i := 0; i < times; i++ {
|
||||
eqs[fields[rand.Intn(len(fields))]] = randVal()
|
||||
}
|
||||
|
||||
b := Update(eqs).From("table1")
|
||||
|
||||
if rgc.allowCond && rand.Intn(1000) >= 500 {
|
||||
b.Where(randCond(fields, 3))
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func randSelectByCondition(dialect string, rgc *randGenConf) *Builder {
|
||||
var b *Builder
|
||||
if rgc.allowSubQuery {
|
||||
cpRgc := *rgc
|
||||
cpRgc.allowSubQuery = false
|
||||
b = Dialect(dialect).Select(randSelects()...).From(randQuery(dialect, &cpRgc), randTableName(0))
|
||||
} else {
|
||||
b = Dialect(dialect).Select(randSelects()...).From(randTableName(0))
|
||||
}
|
||||
if rgc.allowJoin {
|
||||
b = randJoin(b, 3)
|
||||
}
|
||||
if rgc.allowCond && rand.Intn(1000) >= 500 {
|
||||
b = b.Where(randCond(b.selects, 3))
|
||||
}
|
||||
if rgc.allowLimit && rand.Intn(1000) >= 500 {
|
||||
b = randLimit(b)
|
||||
}
|
||||
if rgc.allowOrderBy && rand.Intn(1000) >= 500 {
|
||||
b = randOrderBy(b)
|
||||
}
|
||||
if rgc.allowHaving && rand.Intn(1000) >= 500 {
|
||||
b = randHaving(b)
|
||||
}
|
||||
if rgc.allowGroupBy && rand.Intn(1000) >= 500 {
|
||||
b = randGroupBy(b)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func randDialect() string {
|
||||
dialects := []string{MYSQL, ORACLE, MSSQL, SQLITE, POSTGRES}
|
||||
|
||||
return dialects[rand.Intn(len(dialects))]
|
||||
}
|
||||
|
||||
func randSelects() []string {
|
||||
if rand.Intn(1000) > 900 {
|
||||
return []string{"*"}
|
||||
}
|
||||
|
||||
rdx := rand.Intn(len(queryFields) / 2)
|
||||
return queryFields[rdx:]
|
||||
}
|
||||
|
||||
func randTableName(offset int) string {
|
||||
return fmt.Sprintf("table%v", rand.Intn(10)+offset)
|
||||
}
|
||||
|
||||
func randJoin(b *Builder, lessThan int) *Builder {
|
||||
if lessThan <= 0 {
|
||||
return b
|
||||
}
|
||||
|
||||
times := rand.Intn(lessThan)
|
||||
|
||||
for i := 0; i < times; i++ {
|
||||
tableName := randTableName(i * 10)
|
||||
b = b.Join("", tableName, fmt.Sprintf("%v.id = %v.id", b.TableName(), tableName))
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func randCond(selects []string, lessThan int) Cond {
|
||||
if len(selects) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
cond := NewCond()
|
||||
|
||||
times := rand.Intn(lessThan)
|
||||
for i := 0; i < times; i++ {
|
||||
cond = cond.And(Eq{selects[rand.Intn(len(selects))]: randVal()})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
func randLimit(b *Builder) *Builder {
|
||||
r := rand.Intn(1000) + 1
|
||||
if r > 500 {
|
||||
return b.Limit(r, 1000)
|
||||
}
|
||||
return b.Limit(r)
|
||||
}
|
||||
|
||||
func randOrderBy(b *Builder) *Builder {
|
||||
return b.OrderBy(fmt.Sprintf("%v ASC", b.selects[rand.Intn(len(b.selects))]))
|
||||
}
|
||||
|
||||
func randHaving(b *Builder) *Builder {
|
||||
return b.OrderBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal()))
|
||||
}
|
||||
|
||||
func randGroupBy(b *Builder) *Builder {
|
||||
return b.GroupBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal()))
|
||||
}
|
||||
|
||||
func randVal() interface{} {
|
||||
return expectedValues[rand.Intn(len(expectedValues))]
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Delete creates a delete Builder
|
||||
func Delete(conds ...Cond) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Delete(conds...)
|
||||
}
|
||||
|
||||
func (b *Builder) deleteWriteTo(w Writer) error {
|
||||
if len(b.from) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.cond.WriteTo(w)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilderDelete(t *testing.T) {
|
||||
sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "DELETE FROM table1 WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1}, args)
|
||||
}
|
||||
|
||||
func TestDeleteNoTable(t *testing.T) {
|
||||
_, _, err := Delete(Eq{"b": "0"}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoTableName, err)
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Insert creates an insert Builder
|
||||
func Insert(eq ...interface{}) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Insert(eq...)
|
||||
}
|
||||
|
||||
func (b *Builder) insertSelectWriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "INSERT INTO %s ", b.into); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(b.insertCols) > 0 {
|
||||
fmt.Fprintf(w, "(")
|
||||
for _, col := range b.insertCols {
|
||||
fmt.Fprintf(w, col)
|
||||
}
|
||||
fmt.Fprintf(w, ") ")
|
||||
}
|
||||
|
||||
return b.selectWriteTo(w)
|
||||
}
|
||||
|
||||
func (b *Builder) insertWriteTo(w Writer) error {
|
||||
if len(b.into) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
if len(b.insertCols) <= 0 && b.from == "" {
|
||||
return ErrNoColumnToInsert
|
||||
}
|
||||
|
||||
if b.into != "" && b.from != "" {
|
||||
return b.insertSelectWriteTo(w)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.into); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var args = make([]interface{}, 0)
|
||||
var bs []byte
|
||||
var valBuffer = bytes.NewBuffer(bs)
|
||||
|
||||
for i, col := range b.insertCols {
|
||||
value := b.insertVals[i]
|
||||
fmt.Fprint(w, col)
|
||||
if e, ok := value.(expr); ok {
|
||||
fmt.Fprintf(valBuffer, "(%s)", e.sql)
|
||||
args = append(args, e.args...)
|
||||
} else if value == nil {
|
||||
fmt.Fprintf(valBuffer, `null`)
|
||||
} else {
|
||||
fmt.Fprint(valBuffer, "?")
|
||||
args = append(args, value)
|
||||
}
|
||||
|
||||
if i != len(b.insertCols)-1 {
|
||||
if _, err := fmt.Fprint(w, ","); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(valBuffer, ","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, ") Values ("); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(valBuffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Append(args...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type insertColsSorter struct {
|
||||
cols []string
|
||||
vals []interface{}
|
||||
}
|
||||
|
||||
func (s insertColsSorter) Len() int {
|
||||
return len(s.cols)
|
||||
}
|
||||
|
||||
func (s insertColsSorter) Swap(i, j int) {
|
||||
s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
|
||||
s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
|
||||
}
|
||||
|
||||
func (s insertColsSorter) Less(i, j int) bool {
|
||||
return s.cols[i] < s.cols[j]
|
||||
}
|
||||
|
||||
// Insert sets insert SQL
|
||||
func (b *Builder) Insert(eq ...interface{}) *Builder {
|
||||
if len(eq) > 0 {
|
||||
var paramType = -1
|
||||
for _, e := range eq {
|
||||
switch t := e.(type) {
|
||||
case Eq:
|
||||
if paramType == -1 {
|
||||
paramType = 0
|
||||
}
|
||||
if paramType != 0 {
|
||||
break
|
||||
}
|
||||
for k, v := range t {
|
||||
b.insertCols = append(b.insertCols, k)
|
||||
b.insertVals = append(b.insertVals, v)
|
||||
}
|
||||
case string:
|
||||
if paramType == -1 {
|
||||
paramType = 1
|
||||
}
|
||||
if paramType != 1 {
|
||||
break
|
||||
}
|
||||
b.insertCols = append(b.insertCols, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.insertCols) == len(b.insertVals) {
|
||||
sort.Sort(insertColsSorter{
|
||||
cols: b.insertCols,
|
||||
vals: b.insertVals,
|
||||
})
|
||||
}
|
||||
b.optype = insertType
|
||||
return b
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilderInsert(t *testing.T) {
|
||||
sql, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "INSERT INTO table1 (c,d) Values (1,2)", sql)
|
||||
|
||||
sql, err = Insert(Eq{"e": 3}, Eq{"c": 1}, Eq{"d": 2}).Into("table1").ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "INSERT INTO table1 (c,d,e) Values (1,2,3)", sql)
|
||||
|
||||
sql, err = Insert(Eq{"c": 1, "d": Expr("SELECT b FROM t WHERE d=? LIMIT 1", 2)}).Into("table1").ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "INSERT INTO table1 (c,d) Values (1,(SELECT b FROM t WHERE d=2 LIMIT 1))", sql)
|
||||
|
||||
sql, err = Insert(Eq{"c": 1, "d": 2}).ToBoundSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoTableName, err)
|
||||
assert.EqualValues(t, "", sql)
|
||||
|
||||
sql, err = Insert(Eq{}).Into("table1").ToBoundSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoColumnToInsert, err)
|
||||
assert.EqualValues(t, "", sql)
|
||||
|
||||
sql, err = Insert(Eq{`a`: nil}).Into(`table1`).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, `INSERT INTO table1 (a) Values (null)`, sql)
|
||||
|
||||
sql, args, err := Insert(Eq{`a`: nil, `b`: `str`}).Into(`table1`).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, `INSERT INTO table1 (a,b) Values (null,?)`, sql)
|
||||
assert.EqualValues(t, []interface{}{`str`}, args)
|
||||
}
|
||||
|
||||
func TestBuidlerInsert_Select(t *testing.T) {
|
||||
sql, err := Insert().Into("table1").Select().From("table2").ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "INSERT INTO table1 SELECT * FROM table2", sql)
|
||||
|
||||
sql, err = Insert("a, b").Into("table1").Select("b, c").From("table2").ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "INSERT INTO table1 (a, b) SELECT b, c FROM table2", sql)
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
// InnerJoin sets inner join
|
||||
func (b *Builder) InnerJoin(joinTable, joinCond interface{}) *Builder {
|
||||
return b.Join("INNER", joinTable, joinCond)
|
||||
}
|
||||
|
||||
// LeftJoin sets left join SQL
|
||||
func (b *Builder) LeftJoin(joinTable, joinCond interface{}) *Builder {
|
||||
return b.Join("LEFT", joinTable, joinCond)
|
||||
}
|
||||
|
||||
// RightJoin sets right join SQL
|
||||
func (b *Builder) RightJoin(joinTable, joinCond interface{}) *Builder {
|
||||
return b.Join("RIGHT", joinTable, joinCond)
|
||||
}
|
||||
|
||||
// CrossJoin sets cross join SQL
|
||||
func (b *Builder) CrossJoin(joinTable, joinCond interface{}) *Builder {
|
||||
return b.Join("CROSS", joinTable, joinCond)
|
||||
}
|
||||
|
||||
// FullJoin sets full join SQL
|
||||
func (b *Builder) FullJoin(joinTable, joinCond interface{}) *Builder {
|
||||
return b.Join("FULL", joinTable, joinCond)
|
||||
}
|
||||
|
||||
// Join sets join table and conditions
|
||||
func (b *Builder) Join(joinType string, joinTable, joinCond interface{}) *Builder {
|
||||
switch joinCond.(type) {
|
||||
case Cond:
|
||||
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
|
||||
case string:
|
||||
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
sql, args, err := Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? RIGHT JOIN table3 ON table2.id = table3.tid WHERE a=?",
|
||||
sql)
|
||||
assert.EqualValues(t, []interface{}{1, 3, 1}, args)
|
||||
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
FullJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? FULL JOIN table3 ON table2.id = table3.tid WHERE a=?",
|
||||
sql)
|
||||
assert.EqualValues(t, []interface{}{1, 3, 1}, args)
|
||||
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
CrossJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? CROSS JOIN table3 ON table2.id = table3.tid WHERE a=?",
|
||||
sql)
|
||||
assert.EqualValues(t, []interface{}{1, 3, 1}, args)
|
||||
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
InnerJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? INNER JOIN table3 ON table2.id = table3.tid WHERE a=?",
|
||||
sql)
|
||||
assert.EqualValues(t, []interface{}{1, 3, 1}, args)
|
||||
|
||||
subQuery2 := Select("e").From("table2").Where(Gt{"e": 1})
|
||||
subQuery3 := Select("f").From("table3").Where(Gt{"f": "2"})
|
||||
sql, args, err = Select("c, d").From("table1").LeftJoin(subQuery2, Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
|
||||
InnerJoin(subQuery3, "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN (SELECT e FROM table2 WHERE e>?) ON table1.id=? AND table2.id<? INNER JOIN (SELECT f FROM table3 WHERE f>?) ON table2.id = table3.tid WHERE a=?",
|
||||
sql)
|
||||
assert.EqualValues(t, []interface{}{1, 1, 3, "2", 1}, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b *Builder) limitWriteTo(w Writer) error {
|
||||
if strings.TrimSpace(b.dialect) == "" {
|
||||
return ErrDialectNotSetUp
|
||||
}
|
||||
|
||||
if b.limitation != nil {
|
||||
limit := b.limitation
|
||||
if limit.offset < 0 || limit.limitN <= 0 {
|
||||
return ErrInvalidLimitation
|
||||
}
|
||||
// erase limit condition
|
||||
b.limitation = nil
|
||||
defer func() {
|
||||
b.limitation = limit
|
||||
}()
|
||||
ow := w.(*BytesWriter)
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(b.dialect)) {
|
||||
case ORACLE:
|
||||
if len(b.selects) == 0 {
|
||||
b.selects = append(b.selects, "*")
|
||||
}
|
||||
|
||||
var final *Builder
|
||||
selects := b.selects
|
||||
b.selects = append(selects, "ROWNUM RN")
|
||||
|
||||
var wb *Builder
|
||||
if b.optype == setOpType {
|
||||
wb = Dialect(b.dialect).Select("at.*", "ROWNUM RN").
|
||||
From(b, "at")
|
||||
} else {
|
||||
wb = b
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at").
|
||||
Where(Lte{"at.RN": limit.limitN})
|
||||
} else {
|
||||
sub := Dialect(b.dialect).Select("*").
|
||||
From(b, "at").Where(Lte{"at.RN": limit.offset + limit.limitN})
|
||||
|
||||
final = Dialect(b.dialect).Select(selects...).From(sub, "att").
|
||||
Where(Gt{"att.RN": limit.offset})
|
||||
}
|
||||
|
||||
return final.WriteTo(ow)
|
||||
case SQLITE, MYSQL, POSTGRES:
|
||||
// if type UNION, we need to write previous content back to current writer
|
||||
if b.optype == setOpType {
|
||||
if err := b.WriteTo(ow); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
fmt.Fprint(ow, " LIMIT ", limit.limitN)
|
||||
} else {
|
||||
fmt.Fprintf(ow, " LIMIT %v OFFSET %v", limit.limitN, limit.offset)
|
||||
}
|
||||
case MSSQL:
|
||||
if len(b.selects) == 0 {
|
||||
b.selects = append(b.selects, "*")
|
||||
}
|
||||
|
||||
var final *Builder
|
||||
selects := b.selects
|
||||
b.selects = append(append([]string{fmt.Sprintf("TOP %d %v", limit.limitN+limit.offset, b.selects[0])},
|
||||
b.selects[1:]...), "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN")
|
||||
|
||||
var wb *Builder
|
||||
if b.optype == setOpType {
|
||||
wb = Dialect(b.dialect).Select("*", "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN").
|
||||
From(b, "at")
|
||||
} else {
|
||||
wb = b
|
||||
}
|
||||
|
||||
if limit.offset == 0 {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at")
|
||||
} else {
|
||||
final = Dialect(b.dialect).Select(selects...).From(wb, "at").Where(Gt{"at.RN": limit.offset})
|
||||
}
|
||||
|
||||
return final.WriteTo(ow)
|
||||
default:
|
||||
return ErrNotSupportType
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilder_Limit4Mssql(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/mssql_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
f, err := newFiddler("", MSSQL, sqlFromFile)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, f.sessionCode)
|
||||
|
||||
// simple -- MsSQL style
|
||||
sql, err := Dialect(MSSQL).Select("a", "b", "c").From("table1").
|
||||
OrderBy("a ASC").Limit(5).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT TOP 5 a,b,c,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN FROM table1 ORDER BY a ASC) at", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple with where -- MsSQL style
|
||||
sql, err = Dialect(MSSQL).Select("a", "b", "c").From("table1").
|
||||
Where(Neq{"a": "3"}).OrderBy("a ASC").Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT TOP 15 a,b,c,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN FROM table1 WHERE a<>'3' ORDER BY a ASC) at WHERE at.RN>10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// union with limit -- MsSQL style
|
||||
sql, err = Dialect(MSSQL).Select("a", "b", "c").From(
|
||||
Dialect(MSSQL).Select("a", "b", "c").From("table1").Where(Neq{"a": "1"}).
|
||||
OrderBy("a ASC").Limit(5, 6).Union("ALL",
|
||||
Select("a", "b", "c").From("table1").Where(Neq{"b": "2"}).OrderBy("a DESC").Limit(10)), "at").
|
||||
OrderBy("b DESC").Limit(7, 9).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT TOP 16 a,b,c,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN FROM ((SELECT a,b,c FROM (SELECT TOP 11 a,b,c,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN FROM table1 WHERE a<>'1' ORDER BY a ASC) at WHERE at.RN>6) UNION ALL (SELECT a,b,c FROM (SELECT TOP 10 a,b,c,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN FROM table1 WHERE b<>'2' ORDER BY a DESC) at)) at ORDER BY b DESC) at WHERE at.RN>9", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
}
|
||||
|
||||
func TestBuilder_Limit4MysqlLike(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
f, err := newFiddler("", MYSQL, sqlFromFile)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, f.sessionCode)
|
||||
|
||||
// simple -- MySQL/SQLite/PostgreSQL style
|
||||
sql, err := Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
|
||||
Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM table1 ORDER BY a ASC LIMIT 5 OFFSET 10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple -- MySQL/SQLite/PostgreSQL style
|
||||
sql, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
|
||||
OrderBy("a ASC").Limit(5).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM table1 ORDER BY a ASC LIMIT 5", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple with where -- MySQL/SQLite/PostgreSQL style
|
||||
sql, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
|
||||
Where(Eq{"a": "1", "b": "1"}).OrderBy("a ASC").Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM table1 WHERE a='1' AND b='1' ORDER BY a ASC LIMIT 5 OFFSET 10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// union -- MySQL/SQLite/PostgreSQL style
|
||||
sql, err = Dialect(MYSQL).Select("a", "b", "c").From(
|
||||
Dialect(MYSQL).Select("a", "b", "c").From("table1").Where(Eq{"a": "1"}).OrderBy("a ASC").
|
||||
Limit(5, 9).Union("ALL",
|
||||
Select("a", "b", "c").From("table1").Where(Eq{"a": "2"}).OrderBy("a DESC").Limit(10)), "at").
|
||||
Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM ((SELECT a,b,c FROM table1 WHERE a='1' ORDER BY a ASC LIMIT 5 OFFSET 9) UNION ALL (SELECT a,b,c FROM table1 WHERE a='2' ORDER BY a DESC LIMIT 10)) at LIMIT 5 OFFSET 10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
}
|
||||
|
||||
func TestBuilder_Limit4Oracle(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/oracle_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
f, err := newFiddler("", ORACLE, sqlFromFile)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, f.sessionCode)
|
||||
|
||||
// simple -- OracleSQL style
|
||||
sql, err := Dialect(ORACLE).Select("a", "b", "c").From("table1").OrderBy("a ASC").
|
||||
Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT * FROM (SELECT a,b,c,ROWNUM RN FROM table1 ORDER BY a ASC) at WHERE at.RN<=15) att WHERE att.RN>10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple with join -- OracleSQL style
|
||||
sql, err = Dialect(ORACLE).Select("a", "b", "c", "d").From("table1 t1").
|
||||
InnerJoin("table2 t2", "t1.id = t2.ref_id").OrderBy("a ASC").Limit(5, 10).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c,d FROM (SELECT * FROM (SELECT a,b,c,d,ROWNUM RN FROM table1 t1 INNER JOIN table2 t2 ON t1.id = t2.ref_id ORDER BY a ASC) at WHERE at.RN<=15) att WHERE att.RN>10", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple -- OracleSQL style
|
||||
sql, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").
|
||||
OrderBy("a ASC").Limit(5).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT a,b,c,ROWNUM RN FROM table1 ORDER BY a ASC) at WHERE at.RN<=5", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// simple with where -- OracleSQL style
|
||||
sql, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").Where(Neq{"a": "10", "b": "20"}).
|
||||
OrderBy("a ASC").Limit(5, 1).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT * FROM (SELECT a,b,c,ROWNUM RN FROM table1 WHERE a<>'10' AND b<>'20' ORDER BY a ASC) at WHERE at.RN<=6) att WHERE att.RN>1", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
|
||||
// union with limit -- OracleSQL style
|
||||
sql, err = Dialect(ORACLE).Select("a", "b", "c").From(
|
||||
Dialect(ORACLE).Select("a", "b", "c").From("table1").
|
||||
Where(Neq{"a": "0"}).OrderBy("a ASC").Limit(5, 10).Union("ALL",
|
||||
Select("a", "b", "c").From("table1").Where(Neq{"b": "48"}).
|
||||
OrderBy("a DESC").Limit(10)), "at").
|
||||
Limit(3).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a,b,c FROM (SELECT a,b,c,ROWNUM RN FROM ((SELECT a,b,c FROM (SELECT * FROM (SELECT a,b,c,ROWNUM RN FROM table1 WHERE a<>'0' ORDER BY a ASC) at WHERE at.RN<=15) att WHERE att.RN>10) UNION ALL (SELECT a,b,c FROM (SELECT a,b,c,ROWNUM RN FROM table1 WHERE b<>'48' ORDER BY a DESC) at WHERE at.RN<=10)) at) at WHERE at.RN<=3", sql)
|
||||
assert.NoError(t, f.executableCheck(sql))
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Select creates a select Builder
|
||||
func Select(cols ...string) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Select(cols...)
|
||||
}
|
||||
|
||||
func (b *Builder) selectWriteTo(w Writer) error {
|
||||
if len(b.from) <= 0 && !b.isNested {
|
||||
return ErrNoTableName
|
||||
}
|
||||
|
||||
// perform limit before writing to writer when b.dialect between ORACLE and MSSQL
|
||||
// this avoid a duplicate writing problem in simple limit query
|
||||
if b.limitation != nil && (b.dialect == ORACLE || b.dialect == MSSQL) {
|
||||
return b.limitWriteTo(w)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, "SELECT "); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(b.selects) > 0 {
|
||||
for i, s := range b.selects {
|
||||
if _, err := fmt.Fprint(w, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if i != len(b.selects)-1 {
|
||||
if _, err := fmt.Fprint(w, ","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprint(w, "*"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.subQuery == nil {
|
||||
if _, err := fmt.Fprint(w, " FROM ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if b.cond.IsValid() && len(b.from) <= 0 {
|
||||
return ErrUnnamedDerivedTable
|
||||
}
|
||||
if b.subQuery.dialect != "" && b.dialect != b.subQuery.dialect {
|
||||
return ErrInconsistentDialect
|
||||
}
|
||||
|
||||
// dialect of sub-query will inherit from the main one (if not set up)
|
||||
if b.dialect != "" && b.subQuery.dialect == "" {
|
||||
b.subQuery.dialect = b.dialect
|
||||
}
|
||||
|
||||
switch b.subQuery.optype {
|
||||
case selectType, setOpType:
|
||||
fmt.Fprint(w, " FROM (")
|
||||
if err := b.subQuery.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(b.from) == 0 {
|
||||
fmt.Fprintf(w, ")")
|
||||
} else {
|
||||
fmt.Fprintf(w, ") %v", b.from)
|
||||
}
|
||||
default:
|
||||
return ErrUnexpectedSubQuery
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range b.joins {
|
||||
b, ok := v.joinTable.(*Builder)
|
||||
if ok {
|
||||
if _, err := fmt.Fprintf(w, " %s JOIN (", v.joinType); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, ") ON "); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := v.joinCond.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.cond.IsValid() {
|
||||
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.cond.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.groupBy) > 0 {
|
||||
if _, err := fmt.Fprint(w, " GROUP BY ", b.groupBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.having) > 0 {
|
||||
if _, err := fmt.Fprint(w, " HAVING ", b.having); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.orderBy) > 0 {
|
||||
if _, err := fmt.Fprint(w, " ORDER BY ", b.orderBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.limitation != nil {
|
||||
if err := b.limitWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OrderBy orderBy SQL
|
||||
func (b *Builder) OrderBy(orderBy string) *Builder {
|
||||
b.orderBy = orderBy
|
||||
return b
|
||||
}
|
||||
|
||||
// GroupBy groupby SQL
|
||||
func (b *Builder) GroupBy(groupby string) *Builder {
|
||||
b.groupBy = groupby
|
||||
return b
|
||||
}
|
||||
|
||||
// Having having SQL
|
||||
func (b *Builder) Having(having string) *Builder {
|
||||
b.having = having
|
||||
return b
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilder_Select(t *testing.T) {
|
||||
sql, args, err := Select("c, d").From("table1").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1", sql)
|
||||
assert.EqualValues(t, []interface{}(nil), args)
|
||||
|
||||
sql, args, err = Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c, d FROM table1 WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1}, args)
|
||||
|
||||
_, _, err = Select("c, d").ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoTableName, err)
|
||||
}
|
||||
|
||||
func TestBuilderSelectGroupBy(t *testing.T) {
|
||||
sql, args, err := Select("c").From("table1").GroupBy("c").Having("count(c)=1").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c FROM table1 GROUP BY c HAVING count(c)=1", sql)
|
||||
assert.EqualValues(t, 0, len(args))
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
||||
func TestBuilderSelectOrderBy(t *testing.T) {
|
||||
sql, args, err := Select("c").From("table1").OrderBy("c DESC").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c FROM table1 ORDER BY c DESC", sql)
|
||||
assert.EqualValues(t, 0, len(args))
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
||||
func TestBuilder_From(t *testing.T) {
|
||||
// simple one
|
||||
sql, args, err := Select("c").From("table1").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT c FROM table1", sql)
|
||||
assert.EqualValues(t, 0, len(args))
|
||||
|
||||
// from sub with alias
|
||||
sql, args, err = Select("sub.id").From(Select("id").From("table1").Where(Eq{"a": 1}),
|
||||
"sub").Where(Eq{"b": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT sub.id FROM (SELECT id FROM table1 WHERE a=?) sub WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 1}, args)
|
||||
|
||||
// from sub without alias and with conditions
|
||||
sql, args, err = Select("sub.id").From(Select("id").From("table1").Where(Eq{"a": 1})).Where(Eq{"b": 1}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnnamedDerivedTable, err)
|
||||
|
||||
// from sub without alias and conditions
|
||||
sql, args, err = Select("sub.id").From(Select("id").From("table1").Where(Eq{"a": 1})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT sub.id FROM (SELECT id FROM table1 WHERE a=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{1}, args)
|
||||
|
||||
// from union with alias
|
||||
sql, args, err = Select("sub.id").From(
|
||||
Select("id").From("table1").Where(Eq{"a": 1}).Union(
|
||||
"all", Select("id").From("table1").Where(Eq{"a": 2})), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT sub.id FROM ((SELECT id FROM table1 WHERE a=?) UNION ALL (SELECT id FROM table1 WHERE a=?)) sub WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 2, 1}, args)
|
||||
|
||||
// from union without alias
|
||||
_, _, err = Select("sub.id").From(
|
||||
Select("id").From("table1").Where(Eq{"a": 1}).Union(
|
||||
"all", Select("id").From("table1").Where(Eq{"a": 2}))).Where(Eq{"b": 1}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnnamedDerivedTable, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("c").From(Insert(Eq{"a": 1}).From("table1"), "table1").ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnexpectedSubQuery, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("c").From(Delete(Eq{"a": 1}).From("table1"), "table1").ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnexpectedSubQuery, err)
|
||||
|
||||
// from a sub-query in different dialect
|
||||
_, _, err = MySQL().Select("sub.id").From(
|
||||
Oracle().Select("id").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrInconsistentDialect, err)
|
||||
|
||||
// from a sub-query (dialect set up)
|
||||
sql, args, err = MySQL().Select("sub.id").From(
|
||||
MySQL().Select("id").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT sub.id FROM (SELECT id FROM table1 WHERE a=?) sub WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 1}, args)
|
||||
|
||||
// from a sub-query (dialect not set up)
|
||||
sql, args, err = MySQL().Select("sub.id").From(
|
||||
Select("id").From("table1").Where(Eq{"a": 1}), "sub").Where(Eq{"b": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT sub.id FROM (SELECT id FROM table1 WHERE a=?) sub WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 1}, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b *Builder) setOpWriteTo(w Writer) error {
|
||||
if b.limitation != nil || b.cond.IsValid() ||
|
||||
b.orderBy != "" || b.having != "" || b.groupBy != "" {
|
||||
return ErrNotUnexpectedUnionConditions
|
||||
}
|
||||
|
||||
for idx, o := range b.setOps {
|
||||
current := o.builder
|
||||
if current.optype != selectType {
|
||||
return ErrUnsupportedUnionMembers
|
||||
}
|
||||
|
||||
if len(b.setOps) == 1 {
|
||||
if err := current.selectWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if b.dialect != "" && b.dialect != current.dialect {
|
||||
return ErrInconsistentDialect
|
||||
}
|
||||
|
||||
if idx != 0 {
|
||||
if o.distinctType == "" {
|
||||
fmt.Fprint(w, fmt.Sprintf(" %s ", strings.ToUpper(o.opType)))
|
||||
} else {
|
||||
fmt.Fprint(w, fmt.Sprintf(" %s %s ", strings.ToUpper(o.opType), strings.ToUpper(o.distinctType)))
|
||||
}
|
||||
}
|
||||
fmt.Fprint(w, "(")
|
||||
|
||||
if err := current.selectWriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprint(w, ")")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilder_Union(t *testing.T) {
|
||||
sql, args, err := Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Union("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Union("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) UNION ALL (SELECT * FROM t2 WHERE status=?) UNION DISTINCT (SELECT * FROM t2 WHERE status=?) UNION (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
// sub-query will inherit dialect from the main one
|
||||
sql, args, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
Union("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) UNION ALL (SELECT * FROM t2 WHERE status=? LIMIT 10) UNION (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3"}, args)
|
||||
|
||||
// will raise error
|
||||
_, _, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Oracle().Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrInconsistentDialect, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("*").From("table1").Where(Eq{"a": "1"}).
|
||||
Union("all", Select("*").From("table2").Where(Eq{"a": "2"})).
|
||||
Where(Eq{"a": 2}).Limit(5, 10).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotUnexpectedUnionConditions, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Delete(Eq{"a": 1}).From("t1").
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnsupportedUnionMembers, err)
|
||||
|
||||
// will be overwrote by SELECT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Select("*").From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by DELETE op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Delete(Eq{"status": "1"}).From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by INSERT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Insert(Eq{"status": "1"}).Into("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
||||
func TestBuilder_Intersect(t *testing.T) {
|
||||
sql, args, err := Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Intersect("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Intersect("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) INTERSECT ALL (SELECT * FROM t2 WHERE status=?) INTERSECT DISTINCT (SELECT * FROM t2 WHERE status=?) INTERSECT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
// sub-query will inherit dialect from the main one
|
||||
sql, args, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
Intersect("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) INTERSECT ALL (SELECT * FROM t2 WHERE status=? LIMIT 10) INTERSECT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3"}, args)
|
||||
|
||||
// will raise error
|
||||
_, _, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Oracle().Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrInconsistentDialect, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("*").From("table1").Where(Eq{"a": "1"}).
|
||||
Intersect("all", Select("*").From("table2").Where(Eq{"a": "2"})).
|
||||
Where(Eq{"a": 2}).Limit(5, 10).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotUnexpectedUnionConditions, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Delete(Eq{"a": 1}).From("t1").
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnsupportedUnionMembers, err)
|
||||
|
||||
// will be overwrote by SELECT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Select("*").From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by DELETE op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Delete(Eq{"status": "1"}).From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by INSERT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Insert(Eq{"status": "1"}).Into("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
||||
func TestBuilder_Except(t *testing.T) {
|
||||
sql, args, err := Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Except("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Except("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) EXCEPT ALL (SELECT * FROM t2 WHERE status=?) EXCEPT DISTINCT (SELECT * FROM t2 WHERE status=?) EXCEPT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
// sub-query will inherit dialect from the main one
|
||||
sql, args, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
Except("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) EXCEPT ALL (SELECT * FROM t2 WHERE status=? LIMIT 10) EXCEPT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3"}, args)
|
||||
|
||||
// will raise error
|
||||
_, _, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Oracle().Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrInconsistentDialect, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("*").From("table1").Where(Eq{"a": "1"}).
|
||||
Except("all", Select("*").From("table2").Where(Eq{"a": "2"})).
|
||||
Where(Eq{"a": 2}).Limit(5, 10).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotUnexpectedUnionConditions, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Delete(Eq{"a": 1}).From("t1").
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnsupportedUnionMembers, err)
|
||||
|
||||
// will be overwrote by SELECT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Select("*").From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by DELETE op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Delete(Eq{"status": "1"}).From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by INSERT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Insert(Eq{"status": "1"}).Into("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
||||
func TestBuilder_SetOperations(t *testing.T) {
|
||||
sql, args, err := Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Union("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Intersect("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Except("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) UNION ALL (SELECT * FROM t2 WHERE status=?) INTERSECT DISTINCT (SELECT * FROM t2 WHERE status=?) EXCEPT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Union("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Except("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) INTERSECT ALL (SELECT * FROM t2 WHERE status=?) UNION DISTINCT (SELECT * FROM t2 WHERE status=?) EXCEPT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Except("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Intersect("distinct", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
Union("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) EXCEPT ALL (SELECT * FROM t2 WHERE status=?) INTERSECT DISTINCT (SELECT * FROM t2 WHERE status=?) UNION (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3", "3"}, args)
|
||||
|
||||
// sub-query will inherit dialect from the main one
|
||||
sql, args, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
Intersect("", Select("*").From("t2").Where(Eq{"status": "3"})).
|
||||
ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "(SELECT * FROM t1 WHERE status=?) INTERSECT ALL (SELECT * FROM t2 WHERE status=? LIMIT 10) INTERSECT (SELECT * FROM t2 WHERE status=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "2", "3"}, args)
|
||||
|
||||
// will raise error
|
||||
_, _, err = MySQL().Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Oracle().Select("*").From("t2").Where(Eq{"status": "2"}).Limit(10)).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrInconsistentDialect, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Select("*").From("table1").Where(Eq{"a": "1"}).
|
||||
Intersect("all", Select("*").From("table2").Where(Eq{"a": "2"})).
|
||||
Where(Eq{"a": 2}).Limit(5, 10).
|
||||
ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotUnexpectedUnionConditions, err)
|
||||
|
||||
// will raise error
|
||||
_, _, err = Delete(Eq{"a": 1}).From("t1").
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrUnsupportedUnionMembers, err)
|
||||
|
||||
// will be overwrote by SELECT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Select("*").From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by DELETE op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Delete(Eq{"status": "1"}).From("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
|
||||
// will be overwrote by INSERT op
|
||||
sql, args, err = Select("*").From("t1").Where(Eq{"status": "1"}).
|
||||
Intersect("all", Select("*").From("t2").Where(Eq{"status": "2"})).
|
||||
Insert(Eq{"status": "1"}).Into("t2").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sql, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,657 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type MyInt int
|
||||
|
||||
func TestBuilderCond(t *testing.T) {
|
||||
var cases = []struct {
|
||||
cond Cond
|
||||
sql string
|
||||
args []interface{}
|
||||
}{
|
||||
{
|
||||
Eq{"a": 1}.And(Like{"b", "c"}).Or(Eq{"a": 2}.And(Like{"b", "g"})),
|
||||
"(a=? AND b LIKE ?) OR (a=? AND b LIKE ?)",
|
||||
[]interface{}{1, "%c%", 2, "%g%"},
|
||||
},
|
||||
{
|
||||
Eq{"a": 1}.Or(Like{"b", "c"}).And(Eq{"a": 2}.Or(Like{"b", "g"})),
|
||||
"(a=? OR b LIKE ?) AND (a=? OR b LIKE ?)",
|
||||
[]interface{}{1, "%c%", 2, "%g%"},
|
||||
},
|
||||
{
|
||||
Eq{"d": []string{"e", "f"}},
|
||||
"d IN (?,?)",
|
||||
[]interface{}{"e", "f"},
|
||||
},
|
||||
{
|
||||
Eq{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Eq{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Like{"a", "%1"}.And(Like{"b", "%2"}),
|
||||
"a LIKE ? AND b LIKE ?",
|
||||
[]interface{}{"%1", "%2"},
|
||||
},
|
||||
{
|
||||
Like{"a", "%1"}.Or(Like{"b", "%2"}),
|
||||
"a LIKE ? OR b LIKE ?",
|
||||
[]interface{}{"%1", "%2"},
|
||||
},
|
||||
{
|
||||
Neq{"d": "e"}.Or(Neq{"f": "g"}),
|
||||
"d<>? OR f<>?",
|
||||
[]interface{}{"e", "g"},
|
||||
},
|
||||
{
|
||||
Neq{"d": []string{"e", "f"}},
|
||||
"d NOT IN (?,?)",
|
||||
[]interface{}{"e", "f"},
|
||||
},
|
||||
{
|
||||
Neq{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e<>(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Neq{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e<>(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Lt{"d": 3},
|
||||
"d<?",
|
||||
[]interface{}{3},
|
||||
},
|
||||
{
|
||||
Lt{"d": 3}.And(Lt{"e": 4}),
|
||||
"d<? AND e<?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Lt{"d": 3}.Or(Lt{"e": 4}),
|
||||
"d<? OR e<?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Lt{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e<(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Lt{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e<(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Lte{"d": 3},
|
||||
"d<=?",
|
||||
[]interface{}{3},
|
||||
},
|
||||
{
|
||||
Lte{"d": 3}.And(Lte{"e": 4}),
|
||||
"d<=? AND e<=?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Lte{"d": 3}.Or(Lte{"e": 4}),
|
||||
"d<=? OR e<=?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Lte{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e<=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Lte{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e<=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Gt{"d": 3},
|
||||
"d>?",
|
||||
[]interface{}{3},
|
||||
},
|
||||
{
|
||||
Gt{"d": 3}.And(Gt{"e": 4}),
|
||||
"d>? AND e>?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Gt{"d": 3}.Or(Gt{"e": 4}),
|
||||
"d>? OR e>?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Gt{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e>(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Gt{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e>(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Gte{"d": 3},
|
||||
"d>=?",
|
||||
[]interface{}{3},
|
||||
},
|
||||
{
|
||||
Gte{"d": 3}.And(Gte{"e": 4}),
|
||||
"d>=? AND e>=?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Gte{"d": 3}.Or(Gte{"e": 4}),
|
||||
"d>=? OR e>=?",
|
||||
[]interface{}{3, 4},
|
||||
},
|
||||
{
|
||||
Gte{"e": Select("id").From("f").Where(Eq{"g": 1})},
|
||||
"e>=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Gte{"e": Expr("SELECT id FROM f WHERE g=?", 1)},
|
||||
"e>=(SELECT id FROM f WHERE g=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Between{"d", 0, 2},
|
||||
"d BETWEEN ? AND ?",
|
||||
[]interface{}{0, 2},
|
||||
},
|
||||
{
|
||||
Between{"d", 0, Expr("CAST('2003-01-01' AS DATE)")},
|
||||
"d BETWEEN ? AND CAST('2003-01-01' AS DATE)",
|
||||
[]interface{}{0},
|
||||
},
|
||||
{
|
||||
Between{"d", Expr("CAST('2003-01-01' AS DATE)"), 2},
|
||||
"d BETWEEN CAST('2003-01-01' AS DATE) AND ?",
|
||||
[]interface{}{2},
|
||||
},
|
||||
{
|
||||
Between{"d", Expr("CAST('2003-01-01' AS DATE)"), Expr("CAST('2003-01-01' AS DATE)")},
|
||||
"d BETWEEN CAST('2003-01-01' AS DATE) AND CAST('2003-01-01' AS DATE)",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
Between{"d", 0, 2}.And(Between{"e", 3, 4}),
|
||||
"d BETWEEN ? AND ? AND e BETWEEN ? AND ?",
|
||||
[]interface{}{0, 2, 3, 4},
|
||||
},
|
||||
{
|
||||
Between{"d", 0, 2}.Or(Between{"e", 3, 4}),
|
||||
"d BETWEEN ? AND ? OR e BETWEEN ? AND ?",
|
||||
[]interface{}{0, 2, 3, 4},
|
||||
},
|
||||
{
|
||||
Expr("a < ?", 1),
|
||||
"a < ?",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Expr("a < ?", 1).And(Eq{"b": 2}),
|
||||
"(a < ?) AND b=?",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Expr("a < ?", 1).Or(Neq{"b": 2}),
|
||||
"(a < ?) OR b<>?",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
IsNull{"d"},
|
||||
"d IS NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
IsNull{"d"}.And(IsNull{"e"}),
|
||||
"d IS NULL AND e IS NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
IsNull{"d"}.Or(IsNull{"e"}),
|
||||
"d IS NULL OR e IS NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotNull{"d"},
|
||||
"d IS NOT NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotNull{"d"}.And(NotNull{"e"}),
|
||||
"d IS NOT NULL AND e IS NOT NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotNull{"d"}.Or(NotNull{"e"}),
|
||||
"d IS NOT NULL OR e IS NOT NULL",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", 1, 2).And(NotIn("b", "c", "d")),
|
||||
"a NOT IN (?,?) AND b NOT IN (?,?)",
|
||||
[]interface{}{1, 2, "c", "d"},
|
||||
},
|
||||
{
|
||||
In("a", 1, 2).Or(In("b", "c", "d")),
|
||||
"a IN (?,?) OR b IN (?,?)",
|
||||
[]interface{}{1, 2, "c", "d"},
|
||||
},
|
||||
{
|
||||
In("a", []int{1, 2}).Or(In("b", []string{"c", "d"})),
|
||||
"a IN (?,?) OR b IN (?,?)",
|
||||
[]interface{}{1, 2, "c", "d"},
|
||||
},
|
||||
{
|
||||
In("a", Expr("select id from x where name > ?", "b")),
|
||||
"a IN (select id from x where name > ?)",
|
||||
[]interface{}{"b"},
|
||||
},
|
||||
{
|
||||
In("a", []MyInt{1, 2}).Or(In("b", []string{"c", "d"})),
|
||||
"a IN (?,?) OR b IN (?,?)",
|
||||
[]interface{}{MyInt(1), MyInt(2), "c", "d"},
|
||||
},
|
||||
{
|
||||
In("a", []int{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []int{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []int8{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []int8{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []int16{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []int16{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []int32{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []int32{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []int64{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []int64{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []uint{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []uint{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []uint8{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []uint8{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []uint16{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []uint16{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []uint32{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []uint32{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []uint64{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []uint64{1}),
|
||||
"a IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
In("a", []string{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []interface{}{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []MyInt{}),
|
||||
"0=1",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
In("a", []interface{}{1, 2, 3}).And(Eq{"b": "c"}),
|
||||
"a IN (?,?,?) AND b=?",
|
||||
[]interface{}{1, 2, 3, "c"},
|
||||
},
|
||||
{
|
||||
In("a", Select("id").From("b").Where(Eq{"c": 1})),
|
||||
"a IN (SELECT id FROM b WHERE c=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", Expr("select id from x where name > ?", "b")),
|
||||
"a NOT IN (select id from x where name > ?)",
|
||||
[]interface{}{"b"},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int8{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int8{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int16{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int16{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int32{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int32{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int64{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []int64{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint8{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint8{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint16{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint16{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint32{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint32{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint64{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []uint64{1}),
|
||||
"a NOT IN (?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
NotIn("a", []interface{}{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []string{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []MyInt{}),
|
||||
"0=0",
|
||||
[]interface{}{},
|
||||
},
|
||||
{
|
||||
NotIn("a", []MyInt{1, 2}),
|
||||
"a NOT IN (?,?)",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
NotIn("a", []interface{}{1, 2, 3}).And(Eq{"b": "c"}),
|
||||
"a NOT IN (?,?,?) AND b=?",
|
||||
[]interface{}{1, 2, 3, "c"},
|
||||
},
|
||||
{
|
||||
NotIn("a", []interface{}{1, 2, 3}).Or(Eq{"b": "c"}),
|
||||
"a NOT IN (?,?,?) OR b=?",
|
||||
[]interface{}{1, 2, 3, "c"},
|
||||
},
|
||||
{
|
||||
NotIn("a", Select("id").From("b").Where(Eq{"c": 1})),
|
||||
"a NOT IN (SELECT id FROM b WHERE c=?)",
|
||||
[]interface{}{1},
|
||||
},
|
||||
{
|
||||
Or(Eq{"a": 1, "b": 2}, Eq{"c": 3, "d": 4}),
|
||||
"(a=? AND b=?) OR (c=? AND d=?)",
|
||||
[]interface{}{1, 2, 3, 4},
|
||||
},
|
||||
{
|
||||
Not{Eq{"a": 1, "b": 2}},
|
||||
"NOT (a=? AND b=?)",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Not{Neq{"a": 1, "b": 2}},
|
||||
"NOT (a<>? AND b<>?)",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Not{Eq{"a": 1}.And(Eq{"b": 2})},
|
||||
"NOT (a=? AND b=?)",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Not{Neq{"a": 1}.And(Neq{"b": 2})},
|
||||
"NOT (a<>? AND b<>?)",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Not{Eq{"a": 1}}.And(Neq{"b": 2}),
|
||||
"NOT a=? AND b<>?",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
Not{Eq{"a": 1}}.Or(Neq{"b": 2}),
|
||||
"NOT a=? OR b<>?",
|
||||
[]interface{}{1, 2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, k := range cases {
|
||||
sql, args, err := ToSQL(k.cond)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, k.sql, sql)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
sql2, _, err := ToSQL(k.cond)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, sql, sql2)
|
||||
}
|
||||
|
||||
assert.EqualValues(t, len(args), len(k.args))
|
||||
|
||||
if len(args) > 0 {
|
||||
for i := 0; i < len(args); i++ {
|
||||
assert.EqualValues(t, k.args[i], args[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubquery(t *testing.T) {
|
||||
subb := Select("id").From("table_b").Where(Eq{"b": "a"})
|
||||
b := Select("a, b").From("table_a").Where(
|
||||
Eq{
|
||||
"b_id": subb,
|
||||
"id": 23,
|
||||
},
|
||||
)
|
||||
sql, args, err := b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=?) AND id=?", sql)
|
||||
assert.EqualValues(t, []interface{}{"a", 23}, args)
|
||||
}
|
||||
|
||||
// https://github.com/go-xorm/xorm/issues/820
|
||||
func TestExprCond(t *testing.T) {
|
||||
b := Select("id").From("table1").Where(expr{sql: "a=? OR b=?", args: []interface{}{1, 2}}).Where(Or(Eq{"c": 3}, Eq{"d": 4}))
|
||||
sql, args, err := b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "table1", b.TableName())
|
||||
assert.EqualValues(t, "SELECT id FROM table1 WHERE (a=? OR b=?) AND (c=? OR d=?)", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 2, 3, 4}, args)
|
||||
}
|
||||
|
||||
func TestBuilder_ToBoundSQL(t *testing.T) {
|
||||
newSQL, err := Select("id").From("table").Where(In("a", 1, 2)).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table WHERE a IN (1,2)", newSQL)
|
||||
}
|
||||
|
||||
func TestBuilder_From2(t *testing.T) {
|
||||
b := Select("id").From("table_b", "tb").Where(Eq{"b": "a"})
|
||||
sql, args, err := b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table_b tb WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{"a"}, args)
|
||||
|
||||
b = Select().From("table_b", "tb").Where(Eq{"b": "a"})
|
||||
sql, args, err = b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table_b tb WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{"a"}, args)
|
||||
}
|
||||
|
||||
func TestBuilder_And(t *testing.T) {
|
||||
b := Select("id").From("table_b", "tb").Where(Eq{"b": "a"}).And(Neq{"c": "d"})
|
||||
sql, args, err := b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table_b tb WHERE b=? AND c<>?", sql)
|
||||
assert.EqualValues(t, []interface{}{"a", "d"}, args)
|
||||
}
|
||||
|
||||
func TestBuilder_Or(t *testing.T) {
|
||||
b := Select("id").From("table_b", "tb").Where(Eq{"b": "a"}).Or(Neq{"c": "d"})
|
||||
sql, args, err := b.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table_b tb WHERE b=? OR c<>?", sql)
|
||||
assert.EqualValues(t, []interface{}{"a", "d"}, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// UpdateCond defines an interface that cond could be used with update
|
||||
type UpdateCond interface {
|
||||
IsValid() bool
|
||||
OpWriteTo(op string, w Writer) error
|
||||
}
|
||||
|
||||
// Update creates an update Builder
|
||||
func Update(updates ...Cond) *Builder {
|
||||
builder := &Builder{cond: NewCond()}
|
||||
return builder.Update(updates...)
|
||||
}
|
||||
|
||||
func (b *Builder) updateWriteTo(w Writer) error {
|
||||
if len(b.from) <= 0 {
|
||||
return ErrNoTableName
|
||||
}
|
||||
if len(b.updates) <= 0 {
|
||||
return ErrNoColumnToUpdate
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, s := range b.updates {
|
||||
|
||||
if err := s.OpWriteTo(",", w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i != len(b.updates)-1 {
|
||||
if _, err := fmt.Fprint(w, ","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !b.cond.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.cond.WriteTo(w)
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilderUpdate(t *testing.T) {
|
||||
sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=? WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2, "b": 1}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?,b=? WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2}, Eq{"b": 1}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?,b=? WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2, "b": Incr(1)}).From("table2").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table2 SET a=?,b=b+? WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2, "b": Incr(1), "c": Decr(1), "d": Expr("select count(*) from table2")}).From("table2").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table2 SET a=?,b=b+?,c=c-?,d=(select count(*) from table2) WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1, 1, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2}).Where(Eq{"a": 1}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoTableName, err)
|
||||
|
||||
sql, args, err = Update(Eq{}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNoColumnToUpdate, err)
|
||||
|
||||
var builder = Builder{cond: NewCond()}
|
||||
sql, args, err = builder.Update(Eq{"a": 2, "b": 1}).From("table1").Where(Eq{"a": 1}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?,b=? WHERE a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2, 1, 1}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 1}, Expr("c = c+1")).From("table1").Where(Eq{"b": 2}).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?,c = c+1 WHERE b=?", sql)
|
||||
assert.EqualValues(t, []interface{}{1, 2}, args)
|
||||
|
||||
sql, args, err = Update(Eq{"a": 2}).From("table1").ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?", sql)
|
||||
assert.EqualValues(t, []interface{}{2}, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
// Cond defines an interface
|
||||
type Cond interface {
|
||||
WriteTo(Writer) error
|
||||
And(...Cond) Cond
|
||||
Or(...Cond) Cond
|
||||
IsValid() bool
|
||||
}
|
||||
|
||||
type condEmpty struct{}
|
||||
|
||||
var _ Cond = condEmpty{}
|
||||
|
||||
// NewCond creates an empty condition
|
||||
func NewCond() Cond {
|
||||
return condEmpty{}
|
||||
}
|
||||
|
||||
func (condEmpty) WriteTo(w Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (condEmpty) And(conds ...Cond) Cond {
|
||||
return And(conds...)
|
||||
}
|
||||
|
||||
func (condEmpty) Or(conds ...Cond) Cond {
|
||||
return Or(conds...)
|
||||
}
|
||||
|
||||
func (condEmpty) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
type condAnd []Cond
|
||||
|
||||
var _ Cond = condAnd{}
|
||||
|
||||
// And generates AND conditions
|
||||
func And(conds ...Cond) Cond {
|
||||
var result = make(condAnd, 0, len(conds))
|
||||
for _, cond := range conds {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
continue
|
||||
}
|
||||
result = append(result, cond)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (and condAnd) WriteTo(w Writer) error {
|
||||
for i, cond := range and {
|
||||
_, isOr := cond.(condOr)
|
||||
_, isExpr := cond.(expr)
|
||||
wrap := isOr || isExpr
|
||||
if wrap {
|
||||
fmt.Fprint(w, "(")
|
||||
}
|
||||
|
||||
err := cond.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wrap {
|
||||
fmt.Fprint(w, ")")
|
||||
}
|
||||
|
||||
if i != len(and)-1 {
|
||||
fmt.Fprint(w, " AND ")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (and condAnd) And(conds ...Cond) Cond {
|
||||
return And(and, And(conds...))
|
||||
}
|
||||
|
||||
func (and condAnd) Or(conds ...Cond) Cond {
|
||||
return Or(and, Or(conds...))
|
||||
}
|
||||
|
||||
func (and condAnd) IsValid() bool {
|
||||
return len(and) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Between implmentes between condition
|
||||
type Between struct {
|
||||
Col string
|
||||
LessVal interface{}
|
||||
MoreVal interface{}
|
||||
}
|
||||
|
||||
var _ Cond = Between{}
|
||||
|
||||
// WriteTo write data to Writer
|
||||
func (between Between) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "%s BETWEEN ", between.Col); err != nil {
|
||||
return err
|
||||
}
|
||||
if lv, ok := between.LessVal.(expr); ok {
|
||||
if err := lv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprint(w, "?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(between.LessVal)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, " AND "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mv, ok := between.MoreVal.(expr); ok {
|
||||
if err := mv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := fmt.Fprint(w, "?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(between.MoreVal)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// And implments And with other conditions
|
||||
func (between Between) And(conds ...Cond) Cond {
|
||||
return And(between, And(conds...))
|
||||
}
|
||||
|
||||
// Or implments Or with other conditions
|
||||
func (between Between) Or(conds ...Cond) Cond {
|
||||
return Or(between, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if the condition is valid
|
||||
func (between Between) IsValid() bool {
|
||||
return len(between.Col) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
// WriteMap writes conditions' SQL to Writer, op could be =, <>, >, <, <=, >= and etc.
|
||||
func WriteMap(w Writer, data map[string]interface{}, op string) error {
|
||||
var args = make([]interface{}, 0, len(data))
|
||||
var i = 0
|
||||
keys := make([]string, 0, len(data))
|
||||
for k := range data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
for _, k := range keys {
|
||||
v := data[k]
|
||||
switch v.(type) {
|
||||
case expr:
|
||||
if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(expr).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Builder:
|
||||
if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(*Builder).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if _, err := fmt.Fprintf(w, "%s%s?", k, op); err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
if i != len(data)-1 {
|
||||
if _, err := fmt.Fprint(w, " AND "); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
w.Append(args...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lt defines < condition
|
||||
type Lt map[string]interface{}
|
||||
|
||||
var _ Cond = Lt{}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (lt Lt) WriteTo(w Writer) error {
|
||||
return WriteMap(w, lt, "<")
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (lt Lt) And(conds ...Cond) Cond {
|
||||
return condAnd{lt, And(conds...)}
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (lt Lt) Or(conds ...Cond) Cond {
|
||||
return condOr{lt, Or(conds...)}
|
||||
}
|
||||
|
||||
// IsValid tests if this Eq is valid
|
||||
func (lt Lt) IsValid() bool {
|
||||
return len(lt) > 0
|
||||
}
|
||||
|
||||
// Lte defines <= condition
|
||||
type Lte map[string]interface{}
|
||||
|
||||
var _ Cond = Lte{}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (lte Lte) WriteTo(w Writer) error {
|
||||
return WriteMap(w, lte, "<=")
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (lte Lte) And(conds ...Cond) Cond {
|
||||
return And(lte, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (lte Lte) Or(conds ...Cond) Cond {
|
||||
return Or(lte, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this Eq is valid
|
||||
func (lte Lte) IsValid() bool {
|
||||
return len(lte) > 0
|
||||
}
|
||||
|
||||
// Gt defines > condition
|
||||
type Gt map[string]interface{}
|
||||
|
||||
var _ Cond = Gt{}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (gt Gt) WriteTo(w Writer) error {
|
||||
return WriteMap(w, gt, ">")
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (gt Gt) And(conds ...Cond) Cond {
|
||||
return And(gt, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (gt Gt) Or(conds ...Cond) Cond {
|
||||
return Or(gt, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this Eq is valid
|
||||
func (gt Gt) IsValid() bool {
|
||||
return len(gt) > 0
|
||||
}
|
||||
|
||||
// Gte defines >= condition
|
||||
type Gte map[string]interface{}
|
||||
|
||||
var _ Cond = Gte{}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (gte Gte) WriteTo(w Writer) error {
|
||||
return WriteMap(w, gte, ">=")
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (gte Gte) And(conds ...Cond) Cond {
|
||||
return And(gte, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (gte Gte) Or(conds ...Cond) Cond {
|
||||
return Or(gte, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this Eq is valid
|
||||
func (gte Gte) IsValid() bool {
|
||||
return len(gte) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Incr implements a type used by Eq
|
||||
type Incr int
|
||||
|
||||
// Decr implements a type used by Eq
|
||||
type Decr int
|
||||
|
||||
// Eq defines equals conditions
|
||||
type Eq map[string]interface{}
|
||||
|
||||
var _ Cond = Eq{}
|
||||
|
||||
// OpWriteTo writes conditions with special operator
|
||||
func (eq Eq) OpWriteTo(op string, w Writer) error {
|
||||
var i = 0
|
||||
for _, k := range eq.sortedKeys() {
|
||||
v := eq[k]
|
||||
switch v.(type) {
|
||||
case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
|
||||
if err := In(k, v).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
case expr:
|
||||
if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(expr).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Builder:
|
||||
if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(*Builder).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case Incr:
|
||||
if _, err := fmt.Fprintf(w, "%s=%s+?", k, k); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(int(v.(Incr)))
|
||||
case Decr:
|
||||
if _, err := fmt.Fprintf(w, "%s=%s-?", k, k); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(int(v.(Decr)))
|
||||
case nil:
|
||||
if _, err := fmt.Fprintf(w, "%s=null", k); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if _, err := fmt.Fprintf(w, "%s=?", k); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(v)
|
||||
}
|
||||
if i != len(eq)-1 {
|
||||
if _, err := fmt.Fprint(w, op); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteTo writes SQL to Writer
|
||||
func (eq Eq) WriteTo(w Writer) error {
|
||||
return eq.OpWriteTo(" AND ", w)
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (eq Eq) And(conds ...Cond) Cond {
|
||||
return And(eq, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (eq Eq) Or(conds ...Cond) Cond {
|
||||
return Or(eq, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this Eq is valid
|
||||
func (eq Eq) IsValid() bool {
|
||||
return len(eq) > 0
|
||||
}
|
||||
|
||||
// sortedKeys returns all keys of this Eq sorted with sort.Strings.
|
||||
// It is used internally for consistent ordering when generating
|
||||
// SQL, see https://gitea.com/xorm/builder/issues/10
|
||||
func (eq Eq) sortedKeys() []string {
|
||||
keys := make([]string, 0, len(eq))
|
||||
for key := range eq {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
type expr struct {
|
||||
sql string
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
var _ Cond = expr{}
|
||||
|
||||
// Expr generate customerize SQL
|
||||
func Expr(sql string, args ...interface{}) Cond {
|
||||
return expr{sql, args}
|
||||
}
|
||||
|
||||
func (expr expr) OpWriteTo(op string, w Writer) error {
|
||||
return expr.WriteTo(w)
|
||||
}
|
||||
|
||||
func (expr expr) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprint(w, expr.sql); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(expr.args...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr expr) And(conds ...Cond) Cond {
|
||||
return And(expr, And(conds...))
|
||||
}
|
||||
|
||||
func (expr expr) Or(conds ...Cond) Cond {
|
||||
return Or(expr, Or(conds...))
|
||||
}
|
||||
|
||||
func (expr expr) IsValid() bool {
|
||||
return len(expr.sql) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
type condIf struct {
|
||||
condition bool
|
||||
condTrue Cond
|
||||
condFalse Cond
|
||||
}
|
||||
|
||||
var _ Cond = condIf{}
|
||||
|
||||
// If returns Cond via condition
|
||||
func If(condition bool, condTrue Cond, condFalse ...Cond) Cond {
|
||||
var c = condIf{
|
||||
condition: condition,
|
||||
condTrue: condTrue,
|
||||
}
|
||||
if len(condFalse) > 0 {
|
||||
c.condFalse = condFalse[0]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (condIf condIf) WriteTo(w Writer) error {
|
||||
if condIf.condition {
|
||||
return condIf.condTrue.WriteTo(w)
|
||||
} else if condIf.condFalse != nil {
|
||||
return condIf.condFalse.WriteTo(w)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (condIf condIf) And(conds ...Cond) Cond {
|
||||
return And(condIf, And(conds...))
|
||||
}
|
||||
|
||||
func (condIf condIf) Or(conds ...Cond) Cond {
|
||||
return Or(condIf, Or(conds...))
|
||||
}
|
||||
|
||||
func (condIf condIf) IsValid() bool {
|
||||
if condIf.condition {
|
||||
return condIf.condTrue != nil
|
||||
}
|
||||
return condIf.condFalse != nil
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCond_If(t *testing.T) {
|
||||
cond1 := If(1 > 0, Eq{"a": 1}, Eq{"b": 1})
|
||||
sql, err := ToBoundSQL(cond1)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "a=1", sql)
|
||||
|
||||
cond2 := If(1 < 0, Eq{"a": 1}, Eq{"b": 1})
|
||||
sql, err = ToBoundSQL(cond2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "b=1", sql)
|
||||
|
||||
cond3 := If(1 > 0, cond2, Eq{"c": 1})
|
||||
sql, err = ToBoundSQL(cond3)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "b=1", sql)
|
||||
|
||||
cond4 := If(2 < 0, Eq{"d": "a"})
|
||||
sql, err = ToBoundSQL(cond4)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "", sql)
|
||||
|
||||
cond5 := And(cond1, cond2, cond3, cond4)
|
||||
sql, err = ToBoundSQL(cond5)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "a=1 AND b=1 AND b=1", sql)
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type condIn struct {
|
||||
col string
|
||||
vals []interface{}
|
||||
}
|
||||
|
||||
var _ Cond = condIn{}
|
||||
|
||||
// In generates IN condition
|
||||
func In(col string, values ...interface{}) Cond {
|
||||
return condIn{col, values}
|
||||
}
|
||||
|
||||
func (condIn condIn) handleBlank(w Writer) error {
|
||||
_, err := fmt.Fprint(w, "0=1")
|
||||
return err
|
||||
}
|
||||
|
||||
func (condIn condIn) WriteTo(w Writer) error {
|
||||
if len(condIn.vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
|
||||
switch condIn.vals[0].(type) {
|
||||
case []int8:
|
||||
vals := condIn.vals[0].([]int8)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int16:
|
||||
vals := condIn.vals[0].([]int16)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int:
|
||||
vals := condIn.vals[0].([]int)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int32:
|
||||
vals := condIn.vals[0].([]int32)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int64:
|
||||
vals := condIn.vals[0].([]int64)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint8:
|
||||
vals := condIn.vals[0].([]uint8)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint16:
|
||||
vals := condIn.vals[0].([]uint16)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint:
|
||||
vals := condIn.vals[0].([]uint)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint32:
|
||||
vals := condIn.vals[0].([]uint32)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint64:
|
||||
vals := condIn.vals[0].([]uint64)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []string:
|
||||
vals := condIn.vals[0].([]string)
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []interface{}:
|
||||
vals := condIn.vals[0].([]interface{})
|
||||
if len(vals) <= 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(vals...)
|
||||
case expr:
|
||||
val := condIn.vals[0].(expr)
|
||||
if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := val.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Builder:
|
||||
bd := condIn.vals[0].(*Builder)
|
||||
if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bd.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
v := reflect.ValueOf(condIn.vals[0])
|
||||
if v.Kind() == reflect.Slice {
|
||||
l := v.Len()
|
||||
if l == 0 {
|
||||
return condIn.handleBlank(w)
|
||||
}
|
||||
|
||||
questionMark := strings.Repeat("?,", l)
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
w.Append(v.Index(i).Interface())
|
||||
}
|
||||
} else {
|
||||
questionMark := strings.Repeat("?,", len(condIn.vals))
|
||||
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(condIn.vals...)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (condIn condIn) And(conds ...Cond) Cond {
|
||||
return And(condIn, And(conds...))
|
||||
}
|
||||
|
||||
func (condIn condIn) Or(conds ...Cond) Cond {
|
||||
return Or(condIn, Or(conds...))
|
||||
}
|
||||
|
||||
func (condIn condIn) IsValid() bool {
|
||||
return len(condIn.col) > 0 && len(condIn.vals) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Like defines like condition
|
||||
type Like [2]string
|
||||
|
||||
var _ Cond = Like{"", ""}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (like Like) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "%s LIKE ?", like[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
// FIXME: if use other regular express, this will be failed. but for compatible, keep this
|
||||
if like[1][0] == '%' || like[1][len(like[1])-1] == '%' {
|
||||
w.Append(like[1])
|
||||
} else {
|
||||
w.Append("%" + like[1] + "%")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (like Like) And(conds ...Cond) Cond {
|
||||
return And(like, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (like Like) Or(conds ...Cond) Cond {
|
||||
return Or(like, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this condition is valid
|
||||
func (like Like) IsValid() bool {
|
||||
return len(like[0]) > 0 && len(like[1]) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Neq defines not equal conditions
|
||||
type Neq map[string]interface{}
|
||||
|
||||
var _ Cond = Neq{}
|
||||
|
||||
// WriteTo writes SQL to Writer
|
||||
func (neq Neq) WriteTo(w Writer) error {
|
||||
var args = make([]interface{}, 0, len(neq))
|
||||
var i = 0
|
||||
for _, k := range neq.sortedKeys() {
|
||||
v := neq[k]
|
||||
switch v.(type) {
|
||||
case []int, []int64, []string, []int32, []int16, []int8:
|
||||
if err := NotIn(k, v).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
case expr:
|
||||
if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(expr).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Builder:
|
||||
if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.(*Builder).WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if _, err := fmt.Fprintf(w, "%s<>?", k); err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
if i != len(neq)-1 {
|
||||
if _, err := fmt.Fprint(w, " AND "); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
w.Append(args...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (neq Neq) And(conds ...Cond) Cond {
|
||||
return And(neq, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (neq Neq) Or(conds ...Cond) Cond {
|
||||
return Or(neq, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this condition is valid
|
||||
func (neq Neq) IsValid() bool {
|
||||
return len(neq) > 0
|
||||
}
|
||||
|
||||
// sortedKeys returns all keys of this Neq sorted with sort.Strings.
|
||||
// It is used internally for consistent ordering when generating
|
||||
// SQL, see https://gitea.com/xorm/builder/issues/10
|
||||
func (neq Neq) sortedKeys() []string {
|
||||
keys := make([]string, 0, len(neq))
|
||||
for key := range neq {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Not defines NOT condition
|
||||
type Not [1]Cond
|
||||
|
||||
var _ Cond = Not{}
|
||||
|
||||
// WriteTo writes SQL to Writer
|
||||
func (not Not) WriteTo(w Writer) error {
|
||||
if _, err := fmt.Fprint(w, "NOT "); err != nil {
|
||||
return err
|
||||
}
|
||||
switch not[0].(type) {
|
||||
case condAnd, condOr:
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
case Eq:
|
||||
if len(not[0].(Eq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case Neq:
|
||||
if len(not[0].(Neq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, "("); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := not[0].WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch not[0].(type) {
|
||||
case condAnd, condOr:
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case Eq:
|
||||
if len(not[0].(Eq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case Neq:
|
||||
if len(not[0].(Neq)) > 1 {
|
||||
if _, err := fmt.Fprint(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (not Not) And(conds ...Cond) Cond {
|
||||
return And(not, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (not Not) Or(conds ...Cond) Cond {
|
||||
return Or(not, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this condition is valid
|
||||
func (not Not) IsValid() bool {
|
||||
return not[0] != nil && not[0].IsValid()
|
||||
}
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type condNotIn condIn
|
||||
|
||||
var _ Cond = condNotIn{}
|
||||
|
||||
// NotIn generate NOT IN condition
|
||||
func NotIn(col string, values ...interface{}) Cond {
|
||||
return condNotIn{col, values}
|
||||
}
|
||||
|
||||
func (condNotIn condNotIn) handleBlank(w Writer) error {
|
||||
_, err := fmt.Fprint(w, "0=0")
|
||||
return err
|
||||
}
|
||||
|
||||
func (condNotIn condNotIn) WriteTo(w Writer) error {
|
||||
if len(condNotIn.vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
|
||||
switch condNotIn.vals[0].(type) {
|
||||
case []int8:
|
||||
vals := condNotIn.vals[0].([]int8)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int16:
|
||||
vals := condNotIn.vals[0].([]int16)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int:
|
||||
vals := condNotIn.vals[0].([]int)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int32:
|
||||
vals := condNotIn.vals[0].([]int32)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []int64:
|
||||
vals := condNotIn.vals[0].([]int64)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint8:
|
||||
vals := condNotIn.vals[0].([]uint8)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint16:
|
||||
vals := condNotIn.vals[0].([]uint16)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint:
|
||||
vals := condNotIn.vals[0].([]uint)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint32:
|
||||
vals := condNotIn.vals[0].([]uint32)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []uint64:
|
||||
vals := condNotIn.vals[0].([]uint64)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []string:
|
||||
vals := condNotIn.vals[0].([]string)
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range vals {
|
||||
w.Append(val)
|
||||
}
|
||||
case []interface{}:
|
||||
vals := condNotIn.vals[0].([]interface{})
|
||||
if len(vals) <= 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
questionMark := strings.Repeat("?,", len(vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(vals...)
|
||||
case expr:
|
||||
val := condNotIn.vals[0].(expr)
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := val.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Builder:
|
||||
val := condNotIn.vals[0].(*Builder)
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := val.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, ")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
v := reflect.ValueOf(condNotIn.vals[0])
|
||||
if v.Kind() == reflect.Slice {
|
||||
l := v.Len()
|
||||
if l == 0 {
|
||||
return condNotIn.handleBlank(w)
|
||||
}
|
||||
|
||||
questionMark := strings.Repeat("?,", l)
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
w.Append(v.Index(i).Interface())
|
||||
}
|
||||
} else {
|
||||
questionMark := strings.Repeat("?,", len(condNotIn.vals))
|
||||
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(condNotIn.vals...)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (condNotIn condNotIn) And(conds ...Cond) Cond {
|
||||
return And(condNotIn, And(conds...))
|
||||
}
|
||||
|
||||
func (condNotIn condNotIn) Or(conds ...Cond) Cond {
|
||||
return Or(condNotIn, Or(conds...))
|
||||
}
|
||||
|
||||
func (condNotIn condNotIn) IsValid() bool {
|
||||
return len(condNotIn.col) > 0 && len(condNotIn.vals) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
// IsNull defines IS NULL condition
|
||||
type IsNull [1]string
|
||||
|
||||
var _ Cond = IsNull{""}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (isNull IsNull) WriteTo(w Writer) error {
|
||||
_, err := fmt.Fprintf(w, "%s IS NULL", isNull[0])
|
||||
return err
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (isNull IsNull) And(conds ...Cond) Cond {
|
||||
return And(isNull, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (isNull IsNull) Or(conds ...Cond) Cond {
|
||||
return Or(isNull, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this condition is valid
|
||||
func (isNull IsNull) IsValid() bool {
|
||||
return len(isNull[0]) > 0
|
||||
}
|
||||
|
||||
// NotNull defines NOT NULL condition
|
||||
type NotNull [1]string
|
||||
|
||||
var _ Cond = NotNull{""}
|
||||
|
||||
// WriteTo write SQL to Writer
|
||||
func (notNull NotNull) WriteTo(w Writer) error {
|
||||
_, err := fmt.Fprintf(w, "%s IS NOT NULL", notNull[0])
|
||||
return err
|
||||
}
|
||||
|
||||
// And implements And with other conditions
|
||||
func (notNull NotNull) And(conds ...Cond) Cond {
|
||||
return And(notNull, And(conds...))
|
||||
}
|
||||
|
||||
// Or implements Or with other conditions
|
||||
func (notNull NotNull) Or(conds ...Cond) Cond {
|
||||
return Or(notNull, Or(conds...))
|
||||
}
|
||||
|
||||
// IsValid tests if this condition is valid
|
||||
func (notNull NotNull) IsValid() bool {
|
||||
return len(notNull[0]) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "fmt"
|
||||
|
||||
type condOr []Cond
|
||||
|
||||
var _ Cond = condOr{}
|
||||
|
||||
// Or sets OR conditions
|
||||
func Or(conds ...Cond) Cond {
|
||||
var result = make(condOr, 0, len(conds))
|
||||
for _, cond := range conds {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
continue
|
||||
}
|
||||
result = append(result, cond)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// WriteTo implments Cond
|
||||
func (o condOr) WriteTo(w Writer) error {
|
||||
for i, cond := range o {
|
||||
var needQuote bool
|
||||
switch cond.(type) {
|
||||
case condAnd, expr:
|
||||
needQuote = true
|
||||
case Eq:
|
||||
needQuote = (len(cond.(Eq)) > 1)
|
||||
case Neq:
|
||||
needQuote = (len(cond.(Neq)) > 1)
|
||||
}
|
||||
|
||||
if needQuote {
|
||||
fmt.Fprint(w, "(")
|
||||
}
|
||||
|
||||
err := cond.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if needQuote {
|
||||
fmt.Fprint(w, ")")
|
||||
}
|
||||
|
||||
if i != len(o)-1 {
|
||||
fmt.Fprint(w, " OR ")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o condOr) And(conds ...Cond) Cond {
|
||||
return And(o, And(conds...))
|
||||
}
|
||||
|
||||
func (o condOr) Or(conds ...Cond) Cond {
|
||||
return Or(o, Or(conds...))
|
||||
}
|
||||
|
||||
func (o condOr) IsValid() bool {
|
||||
return len(o) > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCond_NotIn(t *testing.T) {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2016 The XORM Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package builder is a simple and powerful sql builder for Go.
|
||||
|
||||
Make sure you have installed Go 1.1+ and then:
|
||||
|
||||
go get xorm.io/builder
|
||||
|
||||
WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
|
||||
|
||||
1. Eq is a redefine of a map, you can give one or more conditions to Eq
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Eq{"a":1})
|
||||
// a=? [1]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
|
||||
// b=? AND c=? ["c", 0]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
|
||||
// b=? AND c=? ["c", 0]
|
||||
sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
|
||||
// b=? OR b=? ["c", "d"]
|
||||
sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
|
||||
// b IN (?,?) ["c", "d"]
|
||||
sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
|
||||
// b=? AND c IN (?,?) [1, 2, 3]
|
||||
|
||||
2. Neq is the same to Eq
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Neq{"a":1})
|
||||
// a<>? [1]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
|
||||
// b<>? AND c<>? ["c", 0]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
|
||||
// b<>? AND c<>? ["c", 0]
|
||||
sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
|
||||
// b<>? OR b<>? ["c", "d"]
|
||||
sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
|
||||
// b NOT IN (?,?) ["c", "d"]
|
||||
sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
|
||||
// b<>? AND c NOT IN (?,?) [1, 2, 3]
|
||||
|
||||
3. Gt, Gte, Lt, Lte
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
|
||||
// a>? AND b>=? [1, 2]
|
||||
sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
|
||||
// a<? OR b<=? [1, 2]
|
||||
|
||||
4. Like
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Like{"a", "c"})
|
||||
// a LIKE ? [%c%]
|
||||
|
||||
5. Expr you can customerize your sql with Expr
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Expr("a = ? ", 1))
|
||||
// a = ? [1]
|
||||
sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
|
||||
// a=(select id from table where c = ?) [1]
|
||||
|
||||
6. In and NotIn
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(In("a", 1, 2, 3))
|
||||
// a IN (?,?,?) [1,2,3]
|
||||
sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
|
||||
// a IN (?,?,?) [1,2,3]
|
||||
sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
|
||||
// a IN (select id from b where c = ?) [1]
|
||||
|
||||
7. IsNull and NotNull
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(IsNull{"a"})
|
||||
// a IS NULL []
|
||||
sql, args, _ := ToSQL(NotNull{"b"})
|
||||
// b IS NOT NULL []
|
||||
|
||||
8. And(conds ...Cond), And can connect one or more condtions via AND
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
|
||||
|
||||
9. Or(conds ...Cond), Or can connect one or more conditions via Or
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
|
||||
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
|
||||
sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
|
||||
// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
|
||||
|
||||
10. Between
|
||||
|
||||
import . "xorm.io/builder"
|
||||
|
||||
sql, args, _ := ToSQL(Between("a", 1, 2))
|
||||
// a BETWEEN 1 AND 2
|
||||
|
||||
11. define yourself conditions
|
||||
Since Cond is a interface, you can define yourself conditions and compare with them
|
||||
*/
|
||||
package builder
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNotSupportType not supported SQL type error
|
||||
ErrNotSupportType = errors.New("Not supported SQL type")
|
||||
// ErrNoNotInConditions no NOT IN params error
|
||||
ErrNoNotInConditions = errors.New("No NOT IN conditions")
|
||||
// ErrNoInConditions no IN params error
|
||||
ErrNoInConditions = errors.New("No IN conditions")
|
||||
// ErrNeedMoreArguments need more arguments
|
||||
ErrNeedMoreArguments = errors.New("Need more sql arguments")
|
||||
// ErrNoTableName no table name
|
||||
ErrNoTableName = errors.New("No table indicated")
|
||||
// ErrNoColumnToUpdate no column to update
|
||||
ErrNoColumnToUpdate = errors.New("No column(s) to update")
|
||||
// ErrNoColumnToInsert no column to insert
|
||||
ErrNoColumnToInsert = errors.New("No column(s) to insert")
|
||||
// ErrNotSupportDialectType not supported dialect type error
|
||||
ErrNotSupportDialectType = errors.New("Not supported dialect type")
|
||||
// ErrNotUnexpectedUnionConditions using union in a wrong way
|
||||
ErrNotUnexpectedUnionConditions = errors.New("Unexpected conditional fields in UNION query")
|
||||
// ErrUnsupportedUnionMembers unexpected members in UNION query
|
||||
ErrUnsupportedUnionMembers = errors.New("Unexpected members in UNION query")
|
||||
// ErrUnexpectedSubQuery Unexpected sub-query in SELECT query
|
||||
ErrUnexpectedSubQuery = errors.New("Unexpected sub-query in SELECT query")
|
||||
// ErrDialectNotSetUp dialect is not setup yet
|
||||
ErrDialectNotSetUp = errors.New("Dialect is not setup yet, try to use `Dialect(dbType)` at first")
|
||||
// ErrInvalidLimitation offset or limit is not correct
|
||||
ErrInvalidLimitation = errors.New("Offset or limit is not correct")
|
||||
// ErrUnnamedDerivedTable Every derived table must have its own alias
|
||||
ErrUnnamedDerivedTable = errors.New("Every derived table must have its own alias")
|
||||
// ErrInconsistentDialect Inconsistent dialect in same builder
|
||||
ErrInconsistentDialect = errors.New("Inconsistent dialect in same builder")
|
||||
)
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
sql2 "database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func condToSQL(cond Cond) (string, []interface{}, error) {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
w := NewWriter()
|
||||
if err := cond.WriteTo(w); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return w.String(), w.args, nil
|
||||
}
|
||||
|
||||
func condToBoundSQL(cond Cond) (string, error) {
|
||||
if cond == nil || !cond.IsValid() {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
w := NewWriter()
|
||||
if err := cond.WriteTo(w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ConvertToBoundSQL(w.String(), w.args)
|
||||
}
|
||||
|
||||
// ToSQL convert a builder or conditions to SQL and args
|
||||
func ToSQL(cond interface{}) (string, []interface{}, error) {
|
||||
switch cond.(type) {
|
||||
case Cond:
|
||||
return condToSQL(cond.(Cond))
|
||||
case *Builder:
|
||||
return cond.(*Builder).ToSQL()
|
||||
}
|
||||
return "", nil, ErrNotSupportType
|
||||
}
|
||||
|
||||
// ToBoundSQL convert a builder or conditions to parameters bound SQL
|
||||
func ToBoundSQL(cond interface{}) (string, error) {
|
||||
switch cond.(type) {
|
||||
case Cond:
|
||||
return condToBoundSQL(cond.(Cond))
|
||||
case *Builder:
|
||||
return cond.(*Builder).ToBoundSQL()
|
||||
}
|
||||
return "", ErrNotSupportType
|
||||
}
|
||||
|
||||
func noSQLQuoteNeeded(a interface{}) bool {
|
||||
if a == nil {
|
||||
return false
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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 := strings.Builder{}
|
||||
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 namedArg, ok := arg.(sql2.NamedArg); ok {
|
||||
arg = namedArg.Value
|
||||
}
|
||||
|
||||
if noSQLQuoteNeeded(arg) {
|
||||
_, err = fmt.Fprint(&buf, arg)
|
||||
} else {
|
||||
// replace ' -> '' (standard replacement) to avoid critical SQL injection,
|
||||
// NOTICE: may allow some injection like % (or _) in LIKE query
|
||||
_, err = fmt.Fprintf(&buf, "'%v'", strings.Replace(fmt.Sprintf("%v", arg), "'",
|
||||
"''", -1))
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
}
|
||||
_, err := buf.WriteString(sql[start:])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// ConvertPlaceholder replaces the place holder ? to $1, $2 ... or :1, :2 ... according prefix
|
||||
func ConvertPlaceholder(sql, prefix string) (string, error) {
|
||||
buf := strings.Builder{}
|
||||
var i, j, start int
|
||||
var ready = true
|
||||
for ; i < len(sql); i++ {
|
||||
if sql[i] == '\'' && i > 0 && sql[i-1] != '\\' {
|
||||
ready = !ready
|
||||
}
|
||||
if ready && sql[i] == '?' {
|
||||
if _, err := buf.WriteString(sql[start:i]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
start = i + 1
|
||||
j = j + 1
|
||||
|
||||
if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(sql[start:]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
sql2 "database/sql"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"gitea.com/xorm/sqlfiddle"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const placeholderConverterSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=?) AND id=? AND c=? AND d=? AND e=? AND f=?"
|
||||
const placeholderConvertedSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=$1) AND id=$2 AND c=$3 AND d=$4 AND e=$5 AND f=$6"
|
||||
const placeholderBoundSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=1) AND id=2.1 AND c='3' AND d=4 AND e='5' AND f=true"
|
||||
|
||||
func TestNoSQLQuoteNeeded(t *testing.T) {
|
||||
assert.False(t, noSQLQuoteNeeded(nil))
|
||||
}
|
||||
|
||||
func TestPlaceholderConverter(t *testing.T) {
|
||||
var convertCases = []struct {
|
||||
before, after string
|
||||
mark string
|
||||
}{
|
||||
{
|
||||
before: placeholderConverterSQL,
|
||||
after: placeholderConvertedSQL,
|
||||
mark: "$",
|
||||
},
|
||||
{
|
||||
before: "SELECT a, b, 'a?b' FROM table_a WHERE id=?",
|
||||
after: "SELECT a, b, 'a?b' FROM table_a WHERE id=:1",
|
||||
mark: ":",
|
||||
},
|
||||
{
|
||||
before: "SELECT a, b, 'a\\'?b' FROM table_a WHERE id=?",
|
||||
after: "SELECT a, b, 'a\\'?b' FROM table_a WHERE id=$1",
|
||||
mark: "$",
|
||||
},
|
||||
{
|
||||
before: "SELECT a, b, 'a\\'b' FROM table_a WHERE id=?",
|
||||
after: "SELECT a, b, 'a\\'b' FROM table_a WHERE id=$1",
|
||||
mark: "$",
|
||||
},
|
||||
}
|
||||
|
||||
for _, kase := range convertCases {
|
||||
t.Run(kase.before, func(t *testing.T) {
|
||||
newSQL, err := ConvertPlaceholder(kase.before, kase.mark)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, kase.after, newSQL)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPlaceholderConverter(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ConvertPlaceholder(placeholderConverterSQL, "$")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoundSQLConverter(t *testing.T) {
|
||||
newSQL, err := ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, "3", uint(4), "5", true})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, placeholderBoundSQL, newSQL)
|
||||
|
||||
newSQL, err = ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, sql2.Named("any", "3"), uint(4), "5", true})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, placeholderBoundSQL, newSQL)
|
||||
|
||||
newSQL, err = ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, "3", 4, "5"})
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNeedMoreArguments, err)
|
||||
|
||||
newSQL, err = ToBoundSQL(Select("id").From("table").Where(In("a", 1, 2)))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table WHERE a IN (1,2)", newSQL)
|
||||
|
||||
newSQL, err = ToBoundSQL(Eq{"a": 1})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "a=1", newSQL)
|
||||
|
||||
newSQL, err = ToBoundSQL(1)
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotSupportType, err)
|
||||
}
|
||||
|
||||
func TestSQL(t *testing.T) {
|
||||
newSQL, args, err := ToSQL(In("a", 1, 2))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "a IN (?,?)", newSQL)
|
||||
assert.EqualValues(t, []interface{}{1, 2}, args)
|
||||
|
||||
newSQL, args, err = ToSQL(Select("id").From("table").Where(In("a", 1, 2)))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT id FROM table WHERE a IN (?,?)", newSQL)
|
||||
assert.EqualValues(t, []interface{}{1, 2}, args)
|
||||
|
||||
newSQL, args, err = ToSQL(1)
|
||||
assert.Error(t, err)
|
||||
assert.EqualValues(t, ErrNotSupportType, err)
|
||||
}
|
||||
|
||||
type fiddler struct {
|
||||
sessionCode string
|
||||
dbType int
|
||||
f *sqlfiddle.Fiddle
|
||||
}
|
||||
|
||||
func readPreparationSQLFromFile(path string) (string, error) {
|
||||
file, err := os.Open(path)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func newFiddler(fiddleServerAddr, dbDialect, preparationSQL string) (*fiddler, error) {
|
||||
var dbType int
|
||||
switch dbDialect {
|
||||
case MYSQL:
|
||||
dbType = sqlfiddle.Mysql5_6
|
||||
case MSSQL:
|
||||
dbType = sqlfiddle.MSSQL2017
|
||||
case POSTGRES:
|
||||
dbType = sqlfiddle.PostgreSQL96
|
||||
case ORACLE:
|
||||
dbType = sqlfiddle.Oracle11gR2
|
||||
case SQLITE:
|
||||
dbType = sqlfiddle.SQLite_WebSQL
|
||||
default:
|
||||
return nil, ErrNotSupportDialectType
|
||||
}
|
||||
|
||||
f := sqlfiddle.NewFiddle(fiddleServerAddr)
|
||||
response, err := f.CreateSchema(dbType, preparationSQL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fiddler{sessionCode: response.Code, f: f, dbType: dbType}, nil
|
||||
}
|
||||
|
||||
func (f *fiddler) executableCheck(obj interface{}) error {
|
||||
var sql string
|
||||
var err error
|
||||
switch obj.(type) {
|
||||
case *Builder:
|
||||
sql, err = obj.(*Builder).ToBoundSQL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case string:
|
||||
sql = obj.(string)
|
||||
}
|
||||
|
||||
_, err = f.f.RunSQL(f.dbType, f.sessionCode, sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestReadPreparationSQLFromFile(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
fmt.Println(sqlFromFile)
|
||||
}
|
||||
|
||||
func TestNewFiddler(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
f, err := newFiddler("", MYSQL, sqlFromFile)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, f.sessionCode)
|
||||
}
|
||||
|
||||
func TestExecutableCheck(t *testing.T) {
|
||||
sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
|
||||
assert.NoError(t, err)
|
||||
f, err := newFiddler("", MYSQL, sqlFromFile)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, f.sessionCode)
|
||||
|
||||
assert.NoError(t, f.executableCheck("SELECT * FROM table1"))
|
||||
|
||||
err = f.executableCheck("SELECT * FROM table3")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestToSQLInDifferentDialects(t *testing.T) {
|
||||
sql, args, err := Postgres().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=$1 AND b<>$2", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "100"}, args)
|
||||
|
||||
sql, args, err = MySQL().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=? AND b<>?", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "100"}, args)
|
||||
|
||||
sql, args, err = MsSQL().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=@p1 AND b<>@p2", sql)
|
||||
assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
|
||||
|
||||
// test sql.NamedArg in cond
|
||||
sql, args, err = MsSQL().Select().From("table1").Where(Eq{"a": sql2.NamedArg{Name: "param", Value: "1"}}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=@p1 AND b<>@p2", sql)
|
||||
assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
|
||||
|
||||
sql, args, err = Oracle().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=:p1 AND b<>:p2", sql)
|
||||
assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
|
||||
|
||||
// test sql.NamedArg in cond
|
||||
sql, args, err = Oracle().Select().From("table1").Where(Eq{"a": sql2.Named("a", "1")}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=:p1 AND b<>:p2", sql)
|
||||
assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
|
||||
|
||||
sql, args, err = SQLite().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE a=? AND b<>?", sql)
|
||||
assert.EqualValues(t, []interface{}{"1", "100"}, args)
|
||||
}
|
||||
|
||||
func TestToSQLInjectionHarmlessDisposal(t *testing.T) {
|
||||
sql, err := MySQL().Select("*").From("table1").Where(Cond(Eq{"name": "cat';truncate table table1;"})).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "SELECT * FROM table1 WHERE name='cat'';truncate table table1;'", sql)
|
||||
|
||||
sql, err = MySQL().Update(Eq{`a`: 1, `b`: nil}).From(`table1`).ToBoundSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=1,b=null", sql)
|
||||
|
||||
sql, args, err := MySQL().Update(Eq{`a`: 1, `b`: nil}).From(`table1`).ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "UPDATE table1 SET a=?,b=null", sql)
|
||||
assert.EqualValues(t, []interface{}{1}, args)
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
create table table1 (
|
||||
id int primary key,
|
||||
a varchar(40),
|
||||
b varchar(40),
|
||||
c varchar(40)
|
||||
);
|
||||
|
||||
create table table2 (
|
||||
id int primary key,
|
||||
ref_id int,
|
||||
d varchar(40)
|
||||
);
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (0, '0', '0', '0');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (1, '1', '1', '1');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (2, '2', '2', '2');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (3, '3', '3', '3');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (4, '4', '4', '4');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (5, '5', '5', '5');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (6, '6', '6', '6');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (7, '7', '7', '7');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (8, '8', '8', '8');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (9, '9', '9', '9');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (10, '10', '10', '10');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (11, '11', '11', '11');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (12, '12', '12', '12');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (13, '13', '13', '13');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (14, '14', '14', '14');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (15, '15', '15', '15');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (16, '16', '16', '16');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (17, '17', '17', '17');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (18, '18', '18', '18');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (19, '19', '19', '19');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (20, '20', '20', '20');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (21, '21', '21', '21');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (22, '22', '22', '22');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (23, '23', '23', '23');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (24, '24', '24', '24');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (25, '25', '25', '25');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (26, '26', '26', '26');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (27, '27', '27', '27');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (28, '28', '28', '28');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (29, '29', '29', '29');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (30, '30', '30', '30');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (31, '31', '31', '31');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (32, '32', '32', '32');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (33, '33', '33', '33');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (34, '34', '34', '34');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (35, '35', '35', '35');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (36, '36', '36', '36');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (37, '37', '37', '37');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (38, '38', '38', '38');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (39, '39', '39', '39');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (40, '40', '40', '40');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (41, '41', '41', '41');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (42, '42', '42', '42');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (43, '43', '43', '43');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (44, '44', '44', '44');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (45, '45', '45', '45');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (46, '46', '46', '46');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (47, '47', '47', '47');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (48, '48', '48', '48');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (49, '49', '49', '49');
|
||||
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (0, '0', '0');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (1, '1', '1');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (2, '2', '2');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (3, '3', '3');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (4, '4', '4');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (5, '5', '5');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (6, '6', '6');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (7, '7', '7');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (8, '8', '8');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (9, '9', '9');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (10, '10', '10');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (11, '11', '11');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (12, '12', '12');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (13, '13', '13');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (14, '14', '14');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (15, '15', '15');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (16, '16', '16');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (17, '17', '17');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (18, '18', '18');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (19, '19', '19');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (20, '20', '20');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (21, '21', '21');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (22, '22', '22');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (23, '23', '23');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (24, '24', '24');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (25, '25', '25');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (26, '26', '26');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (27, '27', '27');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (28, '28', '28');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (29, '29', '29');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (30, '30', '30');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (31, '31', '31');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (32, '32', '32');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (33, '33', '33');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (34, '34', '34');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (35, '35', '35');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (36, '36', '36');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (37, '37', '37');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (38, '38', '38');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (39, '39', '39');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (40, '40', '40');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (41, '41', '41');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (42, '42', '42');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (43, '43', '43');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (44, '44', '44');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (45, '45', '45');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (46, '46', '46');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (47, '47', '47');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (48, '48', '48');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (49, '49', '49');
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
create table table1 (
|
||||
id int primary key,
|
||||
a varchar(40),
|
||||
b varchar(40),
|
||||
c varchar(40)
|
||||
);
|
||||
|
||||
create table table2 (
|
||||
id int primary key,
|
||||
ref_id int,
|
||||
d varchar(40)
|
||||
);
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (0, '0', '0', '0');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (1, '1', '1', '1');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (2, '2', '2', '2');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (3, '3', '3', '3');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (4, '4', '4', '4');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (5, '5', '5', '5');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (6, '6', '6', '6');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (7, '7', '7', '7');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (8, '8', '8', '8');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (9, '9', '9', '9');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (10, '10', '10', '10');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (11, '11', '11', '11');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (12, '12', '12', '12');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (13, '13', '13', '13');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (14, '14', '14', '14');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (15, '15', '15', '15');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (16, '16', '16', '16');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (17, '17', '17', '17');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (18, '18', '18', '18');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (19, '19', '19', '19');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (20, '20', '20', '20');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (21, '21', '21', '21');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (22, '22', '22', '22');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (23, '23', '23', '23');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (24, '24', '24', '24');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (25, '25', '25', '25');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (26, '26', '26', '26');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (27, '27', '27', '27');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (28, '28', '28', '28');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (29, '29', '29', '29');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (30, '30', '30', '30');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (31, '31', '31', '31');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (32, '32', '32', '32');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (33, '33', '33', '33');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (34, '34', '34', '34');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (35, '35', '35', '35');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (36, '36', '36', '36');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (37, '37', '37', '37');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (38, '38', '38', '38');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (39, '39', '39', '39');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (40, '40', '40', '40');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (41, '41', '41', '41');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (42, '42', '42', '42');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (43, '43', '43', '43');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (44, '44', '44', '44');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (45, '45', '45', '45');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (46, '46', '46', '46');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (47, '47', '47', '47');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (48, '48', '48', '48');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (49, '49', '49', '49');
|
||||
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (0, '0', '0');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (1, '1', '1');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (2, '2', '2');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (3, '3', '3');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (4, '4', '4');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (5, '5', '5');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (6, '6', '6');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (7, '7', '7');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (8, '8', '8');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (9, '9', '9');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (10, '10', '10');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (11, '11', '11');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (12, '12', '12');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (13, '13', '13');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (14, '14', '14');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (15, '15', '15');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (16, '16', '16');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (17, '17', '17');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (18, '18', '18');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (19, '19', '19');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (20, '20', '20');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (21, '21', '21');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (22, '22', '22');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (23, '23', '23');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (24, '24', '24');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (25, '25', '25');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (26, '26', '26');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (27, '27', '27');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (28, '28', '28');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (29, '29', '29');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (30, '30', '30');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (31, '31', '31');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (32, '32', '32');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (33, '33', '33');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (34, '34', '34');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (35, '35', '35');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (36, '36', '36');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (37, '37', '37');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (38, '38', '38');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (39, '39', '39');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (40, '40', '40');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (41, '41', '41');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (42, '42', '42');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (43, '43', '43');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (44, '44', '44');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (45, '45', '45');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (46, '46', '46');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (47, '47', '47');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (48, '48', '48');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (49, '49', '49');
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
create table table1 (
|
||||
id number(9) not null primary key,
|
||||
a varchar2(40),
|
||||
b varchar2(40),
|
||||
c varchar2(40)
|
||||
);
|
||||
|
||||
create table table2 (
|
||||
id number(9) not null primary key,
|
||||
ref_id number(9),
|
||||
d varchar2(40)
|
||||
);
|
||||
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (0, '0', '0', '0');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (1, '1', '1', '1');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (2, '2', '2', '2');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (3, '3', '3', '3');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (4, '4', '4', '4');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (5, '5', '5', '5');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (6, '6', '6', '6');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (7, '7', '7', '7');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (8, '8', '8', '8');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (9, '9', '9', '9');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (10, '10', '10', '10');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (11, '11', '11', '11');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (12, '12', '12', '12');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (13, '13', '13', '13');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (14, '14', '14', '14');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (15, '15', '15', '15');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (16, '16', '16', '16');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (17, '17', '17', '17');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (18, '18', '18', '18');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (19, '19', '19', '19');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (20, '20', '20', '20');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (21, '21', '21', '21');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (22, '22', '22', '22');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (23, '23', '23', '23');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (24, '24', '24', '24');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (25, '25', '25', '25');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (26, '26', '26', '26');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (27, '27', '27', '27');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (28, '28', '28', '28');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (29, '29', '29', '29');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (30, '30', '30', '30');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (31, '31', '31', '31');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (32, '32', '32', '32');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (33, '33', '33', '33');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (34, '34', '34', '34');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (35, '35', '35', '35');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (36, '36', '36', '36');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (37, '37', '37', '37');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (38, '38', '38', '38');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (39, '39', '39', '39');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (40, '40', '40', '40');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (41, '41', '41', '41');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (42, '42', '42', '42');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (43, '43', '43', '43');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (44, '44', '44', '44');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (45, '45', '45', '45');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (46, '46', '46', '46');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (47, '47', '47', '47');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (48, '48', '48', '48');
|
||||
INSERT INTO table1 (id, a, b, c)
|
||||
VALUES (49, '49', '49', '49');
|
||||
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (0, '0', '0');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (1, '1', '1');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (2, '2', '2');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (3, '3', '3');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (4, '4', '4');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (5, '5', '5');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (6, '6', '6');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (7, '7', '7');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (8, '8', '8');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (9, '9', '9');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (10, '10', '10');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (11, '11', '11');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (12, '12', '12');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (13, '13', '13');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (14, '14', '14');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (15, '15', '15');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (16, '16', '16');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (17, '17', '17');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (18, '18', '18');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (19, '19', '19');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (20, '20', '20');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (21, '21', '21');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (22, '22', '22');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (23, '23', '23');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (24, '24', '24');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (25, '25', '25');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (26, '26', '26');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (27, '27', '27');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (28, '28', '28');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (29, '29', '29');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (30, '30', '30');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (31, '31', '31');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (32, '32', '32');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (33, '33', '33');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (34, '34', '34');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (35, '35', '35');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (36, '36', '36');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (37, '37', '37');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (38, '38', '38');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (39, '39', '39');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (40, '40', '40');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (41, '41', '41');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (42, '42', '42');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (43, '43', '43');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (44, '44', '44');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (45, '45', '45');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (46, '46', '46');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (47, '47', '47');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (48, '48', '48');
|
||||
INSERT INTO table2 (id, ref_id, d)
|
||||
VALUES (49, '49', '49');
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Writer defines the interface
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
Append(...interface{})
|
||||
}
|
||||
|
||||
var _ Writer = NewWriter()
|
||||
|
||||
// BytesWriter implments Writer and save SQL in bytes.Buffer
|
||||
type BytesWriter struct {
|
||||
*strings.Builder
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// NewWriter creates a new string writer
|
||||
func NewWriter() *BytesWriter {
|
||||
w := &BytesWriter{
|
||||
Builder: &strings.Builder{},
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// Append appends args to Writer
|
||||
func (w *BytesWriter) Append(args ...interface{}) {
|
||||
w.args = append(w.args, args...)
|
||||
}
|
||||
|
||||
// Args returns args
|
||||
func (w *BytesWriter) Args() []interface{} {
|
||||
return w.args
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ package caches
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import (
|
|||
"regexp"
|
||||
"sync"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"errors"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
)
|
||||
|
||||
// Stmt reprents a stmt objects
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
// URI represents an uri to visit database
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
)
|
||||
|
||||
// TableNameWithSchema will add schema prefix on table name if possible
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package dialects
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package dialects
|
|||
import (
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
// FormatTime format time as column type
|
||||
|
|
|
|||
18
engine.go
18
engine.go
|
|
@ -17,15 +17,15 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
"xorm.io/xorm/tags"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/tags"
|
||||
)
|
||||
|
||||
// Engine is the major struct of xorm, it means a database manager.
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
)
|
||||
|
||||
// EngineGroup defines an engine group
|
||||
|
|
|
|||
14
go.mod
14
go.mod
|
|
@ -1,14 +1,14 @@
|
|||
module xorm.io/xorm
|
||||
module gitea.com/laixyz/xorm
|
||||
|
||||
go 1.11
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a
|
||||
github.com/denisenkom/go-mssqldb v0.9.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/lib/pq v1.7.0
|
||||
github.com/mattn/go-sqlite3 v1.14.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
xorm.io/builder v0.3.7
|
||||
)
|
||||
|
|
|
|||
35
go.sum
35
go.sum
|
|
@ -1,11 +1,9 @@
|
|||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
|
|
@ -18,10 +16,10 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
|
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
|
@ -30,31 +28,21 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
|
@ -63,8 +51,7 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ package integrations
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"gitea.com/laixyz/xorm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ package integrations
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func TestSetExpr(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func TestBuilder(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"gitea.com/laixyz/xorm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type IntId struct {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"strconv"
|
||||
"testing"
|
||||
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func isFloatEq(i, j float64, precision int) bool {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
func TestTransaction(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/laixyz/xorm"
|
||||
"gitea.com/laixyz/xorm/internal/statements"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/internal/statements"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
func TestUpdateMap(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type tempUser struct {
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm"
|
||||
"gitea.com/laixyz/xorm/convert"
|
||||
"gitea.com/laixyz/xorm/internal/json"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
|||
12
interface.go
12
interface.go
|
|
@ -10,12 +10,12 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
// Interface defines the interface which Engine, EngineGroup and Session will implementate.
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) ConvertIDSQL(sqlStr string) string {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package statements
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
type columnMap []string
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
type ErrUnsupportedExprType struct {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) writeInsertOutput(buf *strings.Builder, table *schemas.Table) error {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) GenQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
"xorm.io/xorm/tags"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/convert"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/internal/json"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/tags"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func quoteNeeded(a interface{}) bool {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/laixyz/xorm/caches"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/names"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/tags"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
"xorm.io/xorm/tags"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/convert"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/internal/json"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func (statement *Statement) ifAddColUpdate(col *schemas.Column, includeVersion, includeUpdated, includeNil,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/dialects"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/convert"
|
||||
"gitea.com/laixyz/xorm/dialects"
|
||||
"gitea.com/laixyz/xorm/internal/json"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package log
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
)
|
||||
|
||||
// LogContext represents a log context
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"gitea.com/laixyz/xorm"
|
||||
)
|
||||
|
||||
// MigrateFunc is the func signature for migrating.
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"gitea.com/laixyz/xorm"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
|
|
|
|||
6
rows.go
6
rows.go
|
|
@ -10,9 +10,9 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/builder"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
)
|
||||
|
||||
// Rows rows wrapper a rows to
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/gob"
|
||||
|
||||
"xorm.io/xorm/internal/utils"
|
||||
"gitea.com/laixyz/xorm/internal/utils"
|
||||
)
|
||||
|
||||
type PK []interface{}
|
||||
|
|
|
|||
14
session.go
14
session.go
|
|
@ -18,13 +18,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/convert"
|
||||
"xorm.io/xorm/core"
|
||||
"xorm.io/xorm/internal/json"
|
||||
"xorm.io/xorm/internal/statements"
|
||||
"xorm.io/xorm/log"
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/contexts"
|
||||
"gitea.com/laixyz/xorm/convert"
|
||||
"gitea.com/laixyz/xorm/core"
|
||||
"gitea.com/laixyz/xorm/internal/json"
|
||||
"gitea.com/laixyz/xorm/internal/statements"
|
||||
"gitea.com/laixyz/xorm/log"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
// ErrFieldIsNotExist columns does not exist
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
"gitea.com/laixyz/xorm/schemas"
|
||||
)
|
||||
|
||||
func setColumnInt(bean interface{}, col *schemas.Column, t int64) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue