summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-xorm/builder/builder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-xorm/builder/builder.go')
-rw-r--r--vendor/github.com/go-xorm/builder/builder.go303
1 files changed, 234 insertions, 69 deletions
diff --git a/vendor/github.com/go-xorm/builder/builder.go b/vendor/github.com/go-xorm/builder/builder.go
index 80586ce4e1..ffe86d4dcb 100644
--- a/vendor/github.com/go-xorm/builder/builder.go
+++ b/vendor/github.com/go-xorm/builder/builder.go
@@ -5,7 +5,9 @@
package builder
import (
+ sql2 "database/sql"
"fmt"
+ "sort"
)
type optype byte
@@ -16,6 +18,15 @@ const (
insertType // insert
updateType // update
deleteType // delete
+ unionType // union
+)
+
+const (
+ POSTGRES = "postgres"
+ SQLITE = "sqlite3"
+ MYSQL = "mysql"
+ MSSQL = "mssql"
+ ORACLE = "oracle"
)
type join struct {
@@ -24,68 +35,115 @@ type join struct {
joinCond Cond
}
+type union struct {
+ unionType string
+ builder *Builder
+}
+
+type limit struct {
+ limitN int
+ offset int
+}
+
// Builder describes a SQL statement
type Builder struct {
optype
- tableName string
- cond Cond
- selects []string
- joins []join
- inserts Eq
- updates []Eq
- orderBy string
- groupBy string
- having string
+ dialect string
+ isNested bool
+ into string
+ from string
+ subQuery *Builder
+ cond Cond
+ selects []string
+ joins []join
+ unions []union
+ limitation *limit
+ insertCols []string
+ insertVals []interface{}
+ updates []Eq
+ 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
}
-// Select creates a select Builder
-func Select(cols ...string) *Builder {
- builder := &Builder{cond: NewCond()}
- return builder.Select(cols...)
+// MySQL is shortcut of Dialect(MySQL)
+func MySQL() *Builder {
+ return Dialect(MYSQL)
}
-// Insert creates an insert Builder
-func Insert(eq Eq) *Builder {
- builder := &Builder{cond: NewCond()}
- return builder.Insert(eq)
+// MsSQL is shortcut of Dialect(MsSQL)
+func MsSQL() *Builder {
+ return Dialect(MSSQL)
}
-// Update creates an update Builder
-func Update(updates ...Eq) *Builder {
- builder := &Builder{cond: NewCond()}
- return builder.Update(updates...)
+// Oracle is shortcut of Dialect(Oracle)
+func Oracle() *Builder {
+ return Dialect(ORACLE)
}
-// Delete creates a delete Builder
-func Delete(conds ...Cond) *Builder {
- builder := &Builder{cond: NewCond()}
- return builder.Delete(conds...)
+// 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 {
- b.cond = b.cond.And(cond)
+ if b.cond.IsValid() {
+ b.cond = b.cond.And(cond)
+ } else {
+ b.cond = cond
+ }
return b
}
-// From sets the table name
-func (b *Builder) From(tableName string) *Builder {
- b.tableName = tableName
+// 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 {
- return b.tableName
+ if b.optype == insertType {
+ return b.into
+ }
+ return b.from
}
// Into sets insert table name
func (b *Builder) Into(tableName string) *Builder {
- b.tableName = tableName
+ b.into = tableName
return b
}
-// Join sets join table and contions
+// Join sets join table and conditions
func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
switch joinCond.(type) {
case Cond:
@@ -97,6 +155,50 @@ func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builde
return b
}
+// Union sets union conditions
+func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
+ var builder *Builder
+ if b.optype != unionType {
+ builder = &Builder{cond: NewCond()}
+ builder.optype = unionType
+ builder.dialect = b.dialect
+ builder.selects = b.selects
+
+ currentUnions := b.unions
+ // erase sub unions (actually append to new Builder.unions)
+ b.unions = nil
+
+ for e := range currentUnions {
+ currentUnions[e].builder.dialect = b.dialect
+ }
+
+ builder.unions = append(append(builder.unions, union{"", b}), currentUnions...)
+ } else {
+ builder = b
+ }
+
+ if unionCond != nil {
+ if unionCond.dialect == "" && builder.dialect != "" {
+ unionCond.dialect = builder.dialect
+ }
+
+ builder.unions = append(builder.unions, union{unionTp, unionCond})
+ }
+
+ 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
+}
+
// InnerJoin sets inner join
func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("INNER", joinTable, joinCond)
@@ -125,7 +227,9 @@ func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
// Select sets select SQL
func (b *Builder) Select(cols ...string) *Builder {
b.selects = cols
- b.optype = selectType
+ if b.optype == condType {
+ b.optype = selectType
+ }
return b
}
@@ -141,16 +245,70 @@ func (b *Builder) Or(cond Cond) *Builder {
return b
}
+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 Eq) *Builder {
- b.inserts = eq
+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
}
// Update sets update SQL
func (b *Builder) Update(updates ...Eq) *Builder {
- b.updates = updates
+ b.updates = make([]Eq, 0, len(updates))
+ for _, update := range updates {
+ if update.IsValid() {
+ b.updates = append(b.updates, update)
+ }
+ }
b.optype = updateType
return b
}
@@ -165,8 +323,8 @@ func (b *Builder) Delete(conds ...Cond) *Builder {
// WriteTo implements Writer interface
func (b *Builder) WriteTo(w Writer) error {
switch b.optype {
- case condType:
- return b.cond.WriteTo(w)
+ /*case condType:
+ return b.cond.WriteTo(w)*/
case selectType:
return b.selectWriteTo(w)
case insertType:
@@ -175,6 +333,8 @@ func (b *Builder) WriteTo(w Writer) error {
return b.updateWriteTo(w)
case deleteType:
return b.deleteWriteTo(w)
+ case unionType:
+ return b.unionWriteTo(w)
}
return ErrNotSupportType
@@ -187,43 +347,48 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
return "", nil, err
}
- return w.writer.String(), w.args, nil
-}
+ // 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
+ }
+ }
-// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
-func ConvertPlaceholder(sql, prefix string) (string, error) {
- buf := StringBuilder{}
- var j, start = 0, 0
- for i := 0; i < len(sql); i++ {
- if sql[i] == '?' {
- _, err := buf.WriteString(sql[start:i])
- if err != nil {
- return "", err
- }
- start = i + 1
+ var sql = w.writer.String()
+ var err error
- _, err = buf.WriteString(prefix)
- if err != nil {
- return "", err
- }
+ 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])
+ }
- j = j + 1
- _, err = buf.WriteString(fmt.Sprintf("%d", j))
- if err != nil {
- return "", err
- }
+ 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 buf.String(), nil
+
+ return sql, w.args, nil
}
-// ToSQL convert a builder or condtions 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()
+// ToBoundSQL
+func (b *Builder) ToBoundSQL() (string, error) {
+ w := NewWriter()
+ if err := b.WriteTo(w); err != nil {
+ return "", err
}
- return "", nil, ErrNotSupportType
+
+ return ConvertToBoundSQL(w.writer.String(), w.args)
}