123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // 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(),
- }
- }
|