213 lines
5.0 KiB
Go
213 lines
5.0 KiB
Go
// 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(),
|
|
}
|
|
}
|