You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
5.0 KiB
212 lines
5.0 KiB
// Copyright 2018 Huan Du. All rights reserved. |
|
// Licensed under the MIT license that can be found in the LICENSE file. |
|
|
|
package sqlbuilder |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"strconv" |
|
"strings" |
|
) |
|
|
|
// NewSelectBuilder creates a new SELECT builder. |
|
func NewSelectBuilder() *SelectBuilder { |
|
return DefaultFlavor.NewSelectBuilder() |
|
} |
|
|
|
func newSelectBuilder() *SelectBuilder { |
|
args := &Args{} |
|
return &SelectBuilder{ |
|
Cond: Cond{ |
|
Args: args, |
|
}, |
|
limit: -1, |
|
offset: -1, |
|
args: args, |
|
} |
|
} |
|
|
|
// SelectBuilder is a builder to build SELECT. |
|
type SelectBuilder struct { |
|
Cond |
|
|
|
distinct bool |
|
tables []string |
|
selectCols []string |
|
whereExprs []string |
|
havingExprs []string |
|
groupByCols []string |
|
orderByCols []string |
|
order string |
|
limit int |
|
offset int |
|
|
|
args *Args |
|
} |
|
|
|
// Distinct marks this SELECT as DISTINCT. |
|
func (sb *SelectBuilder) Distinct() *SelectBuilder { |
|
sb.distinct = true |
|
return sb |
|
} |
|
|
|
// Select sets columns in SELECT. |
|
func (sb *SelectBuilder) Select(col ...string) *SelectBuilder { |
|
sb.selectCols = EscapeAll(col...) |
|
return sb |
|
} |
|
|
|
// From sets table names in SELECT. |
|
func (sb *SelectBuilder) From(table ...string) *SelectBuilder { |
|
sb.tables = table |
|
return sb |
|
} |
|
|
|
// Where sets expressions of WHERE in SELECT. |
|
func (sb *SelectBuilder) Where(andExpr ...string) *SelectBuilder { |
|
sb.whereExprs = append(sb.whereExprs, andExpr...) |
|
return sb |
|
} |
|
|
|
// Having sets expressions of HAVING in SELECT. |
|
func (sb *SelectBuilder) Having(andExpr ...string) *SelectBuilder { |
|
sb.havingExprs = append(sb.havingExprs, andExpr...) |
|
return sb |
|
} |
|
|
|
// GroupBy sets columns of GROUP BY in SELECT. |
|
func (sb *SelectBuilder) GroupBy(col ...string) *SelectBuilder { |
|
sb.groupByCols = EscapeAll(col...) |
|
return sb |
|
} |
|
|
|
// OrderBy sets columns of ORDER BY in SELECT. |
|
func (sb *SelectBuilder) OrderBy(col ...string) *SelectBuilder { |
|
sb.orderByCols = EscapeAll(col...) |
|
return sb |
|
} |
|
|
|
// Asc sets order of ORDER BY to ASC. |
|
func (sb *SelectBuilder) Asc() *SelectBuilder { |
|
sb.order = "ASC" |
|
return sb |
|
} |
|
|
|
// Desc sets order of ORDER BY to DESC. |
|
func (sb *SelectBuilder) Desc() *SelectBuilder { |
|
sb.order = "DESC" |
|
return sb |
|
} |
|
|
|
// Limit sets the LIMIT in SELECT. |
|
func (sb *SelectBuilder) Limit(limit int) *SelectBuilder { |
|
sb.limit = limit |
|
return sb |
|
} |
|
|
|
// Offset sets the LIMIT offset in SELECT. |
|
func (sb *SelectBuilder) Offset(offset int) *SelectBuilder { |
|
sb.offset = offset |
|
return sb |
|
} |
|
|
|
// As returns an AS expression. |
|
func (sb *SelectBuilder) As(col, alias string) string { |
|
return fmt.Sprintf("%v AS %v", col, Escape(alias)) |
|
} |
|
|
|
// BuilderAs returns an AS expression wrapping a complex SQL. |
|
// According to SQL syntax, SQL built by builder is surrounded by parens. |
|
func (sb *SelectBuilder) BuilderAs(builder Builder, alias string) string { |
|
return fmt.Sprintf("(%v) AS %v", sb.Var(builder), Escape(alias)) |
|
} |
|
|
|
// String returns the compiled SELECT string. |
|
func (sb *SelectBuilder) String() string { |
|
s, _ := sb.Build() |
|
return s |
|
} |
|
|
|
// Build returns compiled SELECT string and args. |
|
// They can be used in `DB#Query` of package `database/sql` directly. |
|
func (sb *SelectBuilder) Build() (sql string, args []interface{}) { |
|
return sb.BuildWithFlavor(sb.args.Flavor) |
|
} |
|
|
|
// BuildWithFlavor returns compiled SELECT string and args with flavor and initial args. |
|
// They can be used in `DB#Query` of package `database/sql` directly. |
|
func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) { |
|
buf := &bytes.Buffer{} |
|
buf.WriteString("SELECT ") |
|
|
|
if sb.distinct { |
|
buf.WriteString("DISTINCT ") |
|
} |
|
|
|
buf.WriteString(strings.Join(sb.selectCols, ", ")) |
|
buf.WriteString(" FROM ") |
|
buf.WriteString(strings.Join(sb.tables, ", ")) |
|
|
|
if len(sb.whereExprs) > 0 { |
|
buf.WriteString(" WHERE ") |
|
buf.WriteString(strings.Join(sb.whereExprs, " AND ")) |
|
} |
|
|
|
if len(sb.groupByCols) > 0 { |
|
buf.WriteString(" GROUP BY ") |
|
buf.WriteString(strings.Join(sb.groupByCols, ", ")) |
|
|
|
if len(sb.havingExprs) > 0 { |
|
buf.WriteString(" HAVING ") |
|
buf.WriteString(strings.Join(sb.havingExprs, " AND ")) |
|
} |
|
} |
|
|
|
if len(sb.orderByCols) > 0 { |
|
buf.WriteString(" ORDER BY ") |
|
buf.WriteString(strings.Join(sb.orderByCols, ", ")) |
|
|
|
if sb.order != "" { |
|
buf.WriteRune(' ') |
|
buf.WriteString(sb.order) |
|
} |
|
} |
|
|
|
if sb.limit >= 0 { |
|
buf.WriteString(" LIMIT ") |
|
buf.WriteString(strconv.Itoa(sb.limit)) |
|
|
|
if sb.offset >= 0 { |
|
buf.WriteString(" OFFSET ") |
|
buf.WriteString(strconv.Itoa(sb.offset)) |
|
} |
|
} |
|
|
|
return sb.Args.CompileWithFlavor(buf.String(), flavor, initialArg...) |
|
} |
|
|
|
// SetFlavor sets the flavor of compiled sql. |
|
func (sb *SelectBuilder) SetFlavor(flavor Flavor) (old Flavor) { |
|
old = sb.args.Flavor |
|
sb.args.Flavor = flavor |
|
return |
|
} |
|
|
|
// Copy the builder |
|
func (sb *SelectBuilder) Copy() *SelectBuilder { |
|
return &SelectBuilder{ |
|
Cond: sb.Cond, |
|
distinct: sb.distinct, |
|
tables: sb.tables, |
|
selectCols: sb.selectCols, |
|
whereExprs: sb.whereExprs, |
|
havingExprs: sb.havingExprs, |
|
groupByCols: sb.groupByCols, |
|
orderByCols: sb.orderByCols, |
|
order: sb.order, |
|
limit: sb.limit, |
|
offset: sb.offset, |
|
args: sb.args.Copy(), |
|
} |
|
}
|
|
|