diff options
Diffstat (limited to 'vendor/github.com/go-xorm/builder/builder.go')
-rw-r--r-- | vendor/github.com/go-xorm/builder/builder.go | 303 |
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) } |