mirror of
https://github.com/hanzoai/sqlbuilder.git
synced 2026-10-01 00:37:42 +00:00
feature: new builder WhereClause dedicated for WHERE
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- [Basic usage](#basic-usage)
|
||||
- [Pre-defined SQL builders](#pre-defined-sql-builders)
|
||||
- [Build `WHERE` clause](#build-where-clause)
|
||||
- [Share `WHERE` clause among builders](#share-where-clause-among-builders)
|
||||
- [Build SQL for different systems](#build-sql-for-different-systems)
|
||||
- [Using `Struct` as a light weight ORM](#using-struct-as-a-light-weight-orm)
|
||||
- [Nested SQL](#nested-sql)
|
||||
@@ -138,12 +139,12 @@ fmt.Println(args)
|
||||
|
||||
There are many methods for building conditions.
|
||||
|
||||
- [Cond.Equal](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.Equal)/[Cond.E](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.E): `field = value`.
|
||||
- [Cond.NotEqual](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NotEqual)/[Cond.NE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NE): `field <> value`.
|
||||
- [Cond.GreaterThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GreaterThan)/[Cond.G](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.G): `field > value`.
|
||||
- [Cond.GreaterEqualThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GreaterEqualThan)/[Cond.GE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GE): `field >= value`.
|
||||
- [Cond.LessThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LessThan)/[Cond.L](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.L): `field < value`.
|
||||
- [Cond.LessEqualThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LessEqualThan)/[Cond.LE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LE): `field <= value`.
|
||||
- [Cond.Equal](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.Equal)/[Cond.E](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.E)/[Cond.EQ](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.EQ): `field = value`.
|
||||
- [Cond.NotEqual](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NotEqual)/[Cond.NE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NE)/[Cond.NEQ](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NEQ): `field <> value`.
|
||||
- [Cond.GreaterThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GreaterThan)/[Cond.G](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.G)/[Cond.GT](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GT): `field > value`.
|
||||
- [Cond.GreaterEqualThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GreaterEqualThan)/[Cond.GE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GE)/[Cond.GTE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.GTE): `field >= value`.
|
||||
- [Cond.LessThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LessThan)/[Cond.L](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.L)/[Cond.LT](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LT): `field < value`.
|
||||
- [Cond.LessEqualThan](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LessEqualThan)/[Cond.LE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LE)/[Cond.LTE](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.LTE): `field <= value`.
|
||||
- [Cond.In](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.In): `field IN (value1, value2, ...)`.
|
||||
- [Cond.NotIn](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.NotIn): `field NOT IN (value1, value2, ...)`.
|
||||
- [Cond.Like](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.Like): `field LIKE value`.
|
||||
@@ -164,6 +165,36 @@ There are also some methods to combine conditions.
|
||||
- [Cond.And](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.And): Combine conditions with `AND` operator.
|
||||
- [Cond.Or](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#Cond.Or): Combine conditions with `OR` operator.
|
||||
|
||||
### Share `WHERE` clause among builders
|
||||
|
||||
Due to the importance of the `WHERE` statement in SQL, we often need to continuously append conditions and even share some common `WHERE` conditions among different builders. Therefore, we abstract the `WHERE` statement into a `WhereClause` struct, which can be used to create reusable `WHERE` conditions.
|
||||
|
||||
Here is a sample to show how to copy `WHERE` clause from a `SelectBuilder` to an `UpdateBuilder`.
|
||||
|
||||
```go
|
||||
// Build a SQL to select a user from database.
|
||||
sb := Select("name", "level").From("users")
|
||||
sb.Where(
|
||||
sb.Equal("id", 1234),
|
||||
)
|
||||
fmt.Println(sb)
|
||||
|
||||
ub := Update("users")
|
||||
ub.Set(
|
||||
ub.Add("level", 10),
|
||||
)
|
||||
|
||||
// Set the WHERE clause of UPDATE to the WHERE clause of SELECT.
|
||||
ub.WhereClause = sb.WhereClause
|
||||
fmt.Println(ub)
|
||||
|
||||
// Output:
|
||||
// SELECT name, level FROM users WHERE id = ?
|
||||
// UPDATE users SET level = level + ? WHERE id = ?
|
||||
```
|
||||
|
||||
The `WhereClause` is not thread-safe. Read samples for [WhereClause](https://pkg.go.dev/github.com/huandu/go-sqlbuilder#WhereClause) to learn how to use it correctly.
|
||||
|
||||
### Build SQL for different systems
|
||||
|
||||
SQL syntax and parameter marks vary in different systems. In this package, we introduce a concept called "flavor" to smooth out these difference.
|
||||
|
||||
@@ -141,22 +141,7 @@ func (args *Args) CompileWithFlavor(format string, flavor Flavor, initialValue .
|
||||
}
|
||||
|
||||
query = buf.String()
|
||||
|
||||
if len(args.sqlNamedArgs) > 0 {
|
||||
// Stabilize the sequence to make it easier to write test cases.
|
||||
ints := make([]int, 0, len(args.sqlNamedArgs))
|
||||
|
||||
for _, p := range args.sqlNamedArgs {
|
||||
ints = append(ints, p)
|
||||
}
|
||||
|
||||
sort.Ints(ints)
|
||||
|
||||
for _, i := range ints {
|
||||
values = append(values, args.args[i])
|
||||
}
|
||||
}
|
||||
|
||||
values = args.mergeSQLNamedArgs(values)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -253,8 +238,71 @@ func (args *Args) compileArg(buf *stringBuilder, flavor Flavor, values []interfa
|
||||
panic(fmt.Errorf("Args.CompileWithFlavor: invalid flavor %v (%v)", flavor, int(flavor)))
|
||||
}
|
||||
|
||||
values = append(values, arg)
|
||||
namedValues := parseNamedArgs(values)
|
||||
|
||||
if n := len(namedValues); n == 0 {
|
||||
values = append(values, arg)
|
||||
} else {
|
||||
index := len(values) - n
|
||||
values = append(values[:index+1], namedValues...)
|
||||
values[index] = arg
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
func (args *Args) mergeSQLNamedArgs(values []interface{}) []interface{} {
|
||||
if len(args.sqlNamedArgs) == 0 {
|
||||
return values
|
||||
}
|
||||
|
||||
namedValues := parseNamedArgs(values)
|
||||
existingNames := make(map[string]struct{}, len(namedValues))
|
||||
|
||||
for _, v := range namedValues {
|
||||
if a, ok := v.(sql.NamedArg); ok {
|
||||
existingNames[a.Name] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Stabilize the sequence to make it easier to write test cases.
|
||||
ints := make([]int, 0, len(args.sqlNamedArgs))
|
||||
|
||||
for n, p := range args.sqlNamedArgs {
|
||||
if _, ok := existingNames[n]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ints = append(ints, p)
|
||||
}
|
||||
|
||||
sort.Ints(ints)
|
||||
|
||||
for _, i := range ints {
|
||||
values = append(values, args.args[i])
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
func parseNamedArgs(initialValue []interface{}) (namedValues []interface{}) {
|
||||
if len(initialValue) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sql.NamedArgs must be placed at the end of the initial value.
|
||||
i := len(initialValue)
|
||||
|
||||
for ; i > 0; i-- {
|
||||
switch initialValue[i-1].(type) {
|
||||
case sql.NamedArg:
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
namedValues = initialValue[i:]
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cond provides several helper methods to build conditions.
|
||||
type Cond struct {
|
||||
Args *Args
|
||||
}
|
||||
|
||||
// NewCond returns a new Cond.
|
||||
func NewCond() *Cond {
|
||||
return &Cond{
|
||||
Args: &Args{},
|
||||
}
|
||||
}
|
||||
|
||||
// Equal represents "field = value".
|
||||
func (c *Cond) Equal(field string, value interface{}) string {
|
||||
buf := newStringBuilder()
|
||||
@@ -137,7 +140,7 @@ func (c *Cond) In(field string, value ...interface{}) string {
|
||||
buf := newStringBuilder()
|
||||
buf.WriteString(Escape(field))
|
||||
buf.WriteString(" IN (")
|
||||
buf.WriteString(strings.Join(vs, ", "))
|
||||
buf.WriteStrings(vs, ", ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -153,7 +156,7 @@ func (c *Cond) NotIn(field string, value ...interface{}) string {
|
||||
buf := newStringBuilder()
|
||||
buf.WriteString(Escape(field))
|
||||
buf.WriteString(" NOT IN (")
|
||||
buf.WriteString(strings.Join(vs, ", "))
|
||||
buf.WriteStrings(vs, ", ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -218,7 +221,7 @@ func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
|
||||
func (c *Cond) Or(orExpr ...string) string {
|
||||
buf := newStringBuilder()
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(strings.Join(orExpr, " OR "))
|
||||
buf.WriteStrings(orExpr, " OR ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -227,7 +230,7 @@ func (c *Cond) Or(orExpr ...string) string {
|
||||
func (c *Cond) And(andExpr ...string) string {
|
||||
buf := newStringBuilder()
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(strings.Join(andExpr, " AND "))
|
||||
buf.WriteStrings(andExpr, " AND ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -263,7 +266,7 @@ func (c *Cond) Any(field, op string, value ...interface{}) string {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(op)
|
||||
buf.WriteString(" ANY (")
|
||||
buf.WriteString(strings.Join(vs, ", "))
|
||||
buf.WriteStrings(vs, ", ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -281,7 +284,7 @@ func (c *Cond) All(field, op string, value ...interface{}) string {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(op)
|
||||
buf.WriteString(" ALL (")
|
||||
buf.WriteString(strings.Join(vs, ", "))
|
||||
buf.WriteStrings(vs, ", ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -299,7 +302,7 @@ func (c *Cond) Some(field, op string, value ...interface{}) string {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(op)
|
||||
buf.WriteString(" SOME (")
|
||||
buf.WriteString(strings.Join(vs, ", "))
|
||||
buf.WriteStrings(vs, ", ")
|
||||
buf.WriteString(")")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ func (ctb *CreateTableBuilder) BuildWithFlavor(flavor Flavor, initialArg ...inte
|
||||
defs = append(defs, strings.Join(def, " "))
|
||||
}
|
||||
|
||||
buf.WriteString(strings.Join(defs, ", "))
|
||||
buf.WriteStrings(defs, ", ")
|
||||
buf.WriteRune(')')
|
||||
|
||||
ctb.injection.WriteTo(buf, createTableMarkerAfterDefine)
|
||||
|
||||
@@ -5,7 +5,6 @@ package sqlbuilder
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,7 +22,11 @@ func NewDeleteBuilder() *DeleteBuilder {
|
||||
|
||||
func newDeleteBuilder() *DeleteBuilder {
|
||||
args := &Args{}
|
||||
proxy := &whereClauseProxy{}
|
||||
return &DeleteBuilder{
|
||||
whereClauseProxy: proxy,
|
||||
whereClauseExpr: args.Add(proxy),
|
||||
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
@@ -35,10 +38,13 @@ func newDeleteBuilder() *DeleteBuilder {
|
||||
|
||||
// DeleteBuilder is a builder to build DELETE.
|
||||
type DeleteBuilder struct {
|
||||
*WhereClause
|
||||
Cond
|
||||
|
||||
whereClauseProxy *whereClauseProxy
|
||||
whereClauseExpr string
|
||||
|
||||
table string
|
||||
whereExprs []string
|
||||
orderByCols []string
|
||||
order string
|
||||
limit int
|
||||
@@ -65,11 +71,25 @@ func (db *DeleteBuilder) DeleteFrom(table string) *DeleteBuilder {
|
||||
|
||||
// Where sets expressions of WHERE in DELETE.
|
||||
func (db *DeleteBuilder) Where(andExpr ...string) *DeleteBuilder {
|
||||
db.whereExprs = append(db.whereExprs, andExpr...)
|
||||
if db.WhereClause == nil {
|
||||
db.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
db.WhereClause.AddWhereExpr(db.args, andExpr...)
|
||||
db.marker = deleteMarkerAfterWhere
|
||||
return db
|
||||
}
|
||||
|
||||
// AddWhereClause adds all clauses in the whereClause to SELECT.
|
||||
func (db *DeleteBuilder) AddWhereClause(whereClause *WhereClause) *DeleteBuilder {
|
||||
if db.WhereClause == nil {
|
||||
db.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
db.WhereClause.AddWhereClause(whereClause)
|
||||
return db
|
||||
}
|
||||
|
||||
// OrderBy sets columns of ORDER BY in DELETE.
|
||||
func (db *DeleteBuilder) OrderBy(col ...string) *DeleteBuilder {
|
||||
db.orderByCols = col
|
||||
@@ -123,16 +143,19 @@ func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
db.injection.WriteTo(buf, deleteMarkerAfterDeleteFrom)
|
||||
|
||||
if len(db.whereExprs) > 0 {
|
||||
buf.WriteLeadingString("WHERE ")
|
||||
buf.WriteString(strings.Join(db.whereExprs, " AND "))
|
||||
if db.WhereClause != nil {
|
||||
db.whereClauseProxy.WhereClause = db.WhereClause
|
||||
defer func() {
|
||||
db.whereClauseProxy.WhereClause = nil
|
||||
}()
|
||||
|
||||
buf.WriteLeadingString(db.whereClauseExpr)
|
||||
db.injection.WriteTo(buf, deleteMarkerAfterWhere)
|
||||
}
|
||||
|
||||
if len(db.orderByCols) > 0 {
|
||||
buf.WriteLeadingString("ORDER BY ")
|
||||
buf.WriteString(strings.Join(db.orderByCols, ", "))
|
||||
buf.WriteStrings(db.orderByCols, ", ")
|
||||
|
||||
if db.order != "" {
|
||||
buf.WriteRune(' ')
|
||||
|
||||
+2
-6
@@ -3,10 +3,6 @@
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// injection is a helper type to manage injected SQLs in all builders.
|
||||
type injection struct {
|
||||
markerSQLs map[injectionMarker][]string
|
||||
@@ -36,6 +32,6 @@ func (injection *injection) WriteTo(buf *stringBuilder, marker injectionMarker)
|
||||
return
|
||||
}
|
||||
|
||||
s := strings.Join(sqls, " ")
|
||||
buf.WriteLeadingString(s)
|
||||
buf.WriteLeadingString("")
|
||||
buf.WriteStrings(sqls, " ")
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
ib.injection.WriteTo(buf, insertMarkerAfterInsertInto)
|
||||
if len(ib.cols) > 0 {
|
||||
buf.WriteLeadingString("(")
|
||||
buf.WriteString(strings.Join(ib.cols, ", "))
|
||||
buf.WriteStrings(ib.cols, ", ")
|
||||
buf.WriteString(")")
|
||||
|
||||
ib.injection.WriteTo(buf, insertMarkerAfterCols)
|
||||
@@ -156,7 +156,7 @@ func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
buf.WriteLeadingString("VALUES ")
|
||||
values := make([]string, 0, len(ib.values))
|
||||
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
|
||||
buf.WriteString(strings.Join(values, ", "))
|
||||
buf.WriteStrings(values, ", ")
|
||||
}
|
||||
|
||||
buf.WriteString(" SELECT 1 from DUAL")
|
||||
@@ -176,7 +176,7 @@ func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
if len(ib.cols) > 0 {
|
||||
buf.WriteLeadingString("(")
|
||||
buf.WriteString(strings.Join(ib.cols, ", "))
|
||||
buf.WriteStrings(ib.cols, ", ")
|
||||
buf.WriteString(")")
|
||||
|
||||
ib.injection.WriteTo(buf, insertMarkerAfterCols)
|
||||
@@ -198,7 +198,7 @@ func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
|
||||
}
|
||||
|
||||
buf.WriteString(strings.Join(values, ", "))
|
||||
buf.WriteStrings(values, ", ")
|
||||
}
|
||||
|
||||
ib.injection.WriteTo(buf, insertMarkerAfterValues)
|
||||
|
||||
+2
-2
@@ -101,9 +101,9 @@ func Tuple(values ...interface{}) interface{} {
|
||||
// TupleNames joins names with tuple format.
|
||||
// The names is not escaped. Use `EscapeAll` to escape them if necessary.
|
||||
func TupleNames(names ...string) string {
|
||||
buf := &strings.Builder{}
|
||||
buf := newStringBuilder()
|
||||
buf.WriteRune('(')
|
||||
buf.WriteString(strings.Join(names, ", "))
|
||||
buf.WriteStrings(names, ", ")
|
||||
buf.WriteRune(')')
|
||||
|
||||
return buf.String()
|
||||
|
||||
@@ -42,7 +42,11 @@ func NewSelectBuilder() *SelectBuilder {
|
||||
|
||||
func newSelectBuilder() *SelectBuilder {
|
||||
args := &Args{}
|
||||
proxy := &whereClauseProxy{}
|
||||
return &SelectBuilder{
|
||||
whereClauseProxy: proxy,
|
||||
whereClauseExpr: args.Add(proxy),
|
||||
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
@@ -55,15 +59,18 @@ func newSelectBuilder() *SelectBuilder {
|
||||
|
||||
// SelectBuilder is a builder to build SELECT.
|
||||
type SelectBuilder struct {
|
||||
*WhereClause
|
||||
Cond
|
||||
|
||||
whereClauseProxy *whereClauseProxy
|
||||
whereClauseExpr string
|
||||
|
||||
distinct bool
|
||||
tables []string
|
||||
selectCols []string
|
||||
joinOptions []JoinOption
|
||||
joinTables []string
|
||||
joinExprs [][]string
|
||||
whereExprs []string
|
||||
havingExprs []string
|
||||
groupByCols []string
|
||||
orderByCols []string
|
||||
@@ -140,11 +147,25 @@ func (sb *SelectBuilder) JoinWithOption(option JoinOption, table string, onExpr
|
||||
|
||||
// Where sets expressions of WHERE in SELECT.
|
||||
func (sb *SelectBuilder) Where(andExpr ...string) *SelectBuilder {
|
||||
sb.whereExprs = append(sb.whereExprs, andExpr...)
|
||||
if sb.WhereClause == nil {
|
||||
sb.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
sb.WhereClause.AddWhereExpr(sb.args, andExpr...)
|
||||
sb.marker = selectMarkerAfterWhere
|
||||
return sb
|
||||
}
|
||||
|
||||
// AddWhereClause adds all clauses in the whereClause to SELECT.
|
||||
func (sb *SelectBuilder) AddWhereClause(whereClause *WhereClause) *SelectBuilder {
|
||||
if sb.WhereClause == nil {
|
||||
sb.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
sb.WhereClause.AddWhereClause(whereClause)
|
||||
return sb
|
||||
}
|
||||
|
||||
// Having sets expressions of HAVING in SELECT.
|
||||
func (sb *SelectBuilder) Having(andExpr ...string) *SelectBuilder {
|
||||
sb.havingExprs = append(sb.havingExprs, andExpr...)
|
||||
@@ -273,15 +294,16 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
var selectCols = make([]string, 0, len(sb.selectCols))
|
||||
for i := range sb.selectCols {
|
||||
cols := strings.SplitN(sb.selectCols[i], ".", 2)
|
||||
|
||||
if len(cols) == 1 {
|
||||
selectCols = append(selectCols, cols[0])
|
||||
} else {
|
||||
selectCols = append(selectCols, cols[1])
|
||||
}
|
||||
}
|
||||
buf.WriteString(strings.Join(selectCols, ", "))
|
||||
buf.WriteStrings(selectCols, ", ")
|
||||
} else {
|
||||
buf.WriteString(strings.Join(sb.selectCols, ", "))
|
||||
buf.WriteStrings(sb.selectCols, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +319,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
var selectCols = make([]string, 0, len(sb.selectCols)+1)
|
||||
selectCols = append(selectCols, "ROWNUM r")
|
||||
|
||||
for i := range sb.selectCols {
|
||||
cols := strings.SplitN(sb.selectCols[i], ".", 2)
|
||||
if len(cols) == 1 {
|
||||
@@ -305,16 +328,16 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
selectCols = append(selectCols, cols[1])
|
||||
}
|
||||
}
|
||||
buf.WriteString(strings.Join(selectCols, ", "))
|
||||
|
||||
buf.WriteStrings(selectCols, ", ")
|
||||
buf.WriteLeadingString("FROM ( SELECT ")
|
||||
buf.WriteString(strings.Join(sb.selectCols, ", "))
|
||||
buf.WriteStrings(sb.selectCols, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
if len(sb.tables) > 0 {
|
||||
buf.WriteLeadingString("FROM ")
|
||||
buf.WriteString(strings.Join(sb.tables, ", "))
|
||||
buf.WriteStrings(sb.tables, ", ")
|
||||
}
|
||||
|
||||
sb.injection.WriteTo(buf, selectMarkerAfterFrom)
|
||||
@@ -329,7 +352,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
if exprs := sb.joinExprs[i]; len(exprs) > 0 {
|
||||
buf.WriteString(" ON ")
|
||||
buf.WriteString(strings.Join(sb.joinExprs[i], " AND "))
|
||||
buf.WriteStrings(sb.joinExprs[i], " AND ")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,20 +360,23 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
sb.injection.WriteTo(buf, selectMarkerAfterJoin)
|
||||
}
|
||||
|
||||
if len(sb.whereExprs) > 0 {
|
||||
buf.WriteLeadingString("WHERE ")
|
||||
buf.WriteString(strings.Join(sb.whereExprs, " AND "))
|
||||
if sb.WhereClause != nil {
|
||||
sb.whereClauseProxy.WhereClause = sb.WhereClause
|
||||
defer func() {
|
||||
sb.whereClauseProxy.WhereClause = nil
|
||||
}()
|
||||
|
||||
buf.WriteLeadingString(sb.whereClauseExpr)
|
||||
sb.injection.WriteTo(buf, selectMarkerAfterWhere)
|
||||
}
|
||||
|
||||
if len(sb.groupByCols) > 0 {
|
||||
buf.WriteLeadingString("GROUP BY ")
|
||||
buf.WriteString(strings.Join(sb.groupByCols, ", "))
|
||||
buf.WriteStrings(sb.groupByCols, ", ")
|
||||
|
||||
if len(sb.havingExprs) > 0 {
|
||||
buf.WriteString(" HAVING ")
|
||||
buf.WriteString(strings.Join(sb.havingExprs, " AND "))
|
||||
buf.WriteStrings(sb.havingExprs, " AND ")
|
||||
}
|
||||
|
||||
sb.injection.WriteTo(buf, selectMarkerAfterGroupBy)
|
||||
@@ -358,7 +384,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
if len(sb.orderByCols) > 0 {
|
||||
buf.WriteLeadingString("ORDER BY ")
|
||||
buf.WriteString(strings.Join(sb.orderByCols, ", "))
|
||||
buf.WriteStrings(sb.orderByCols, ", ")
|
||||
|
||||
if sb.order != "" {
|
||||
buf.WriteRune(' ')
|
||||
@@ -422,7 +448,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
if oraclePage {
|
||||
buf.WriteString(" ) ")
|
||||
if len(sb.tables) > 0 {
|
||||
buf.WriteString(strings.Join(sb.tables, ", "))
|
||||
buf.WriteStrings(sb.tables, ", ")
|
||||
}
|
||||
|
||||
min := sb.offset
|
||||
|
||||
+10
-3
@@ -61,19 +61,26 @@ func ExampleSelectBuilder_advancedUsage() {
|
||||
sb := NewSelectBuilder()
|
||||
innerSb := NewSelectBuilder()
|
||||
|
||||
// Named arguments are supported.
|
||||
start := sql.Named("start", 1234567890)
|
||||
end := sql.Named("end", 1234599999)
|
||||
level := sql.Named("level", 20)
|
||||
|
||||
sb.Select("id", "name")
|
||||
sb.From(
|
||||
sb.BuilderAs(innerSb, "user"),
|
||||
)
|
||||
sb.Where(
|
||||
sb.In("status", Flatten([]int{1, 2, 3})...),
|
||||
sb.Between("created_at", sql.Named("start", 1234567890), sql.Named("end", 1234599999)),
|
||||
sb.Between("created_at", start, end),
|
||||
)
|
||||
sb.OrderBy("modified_at").Desc()
|
||||
|
||||
innerSb.Select("*")
|
||||
innerSb.From("banned")
|
||||
innerSb.Where(
|
||||
innerSb.GreaterThan("level", level),
|
||||
innerSb.LessEqualThan("updated_at", end),
|
||||
innerSb.NotIn("name", Flatten([]string{"Huan Du", "Charmy Liu"})...),
|
||||
)
|
||||
|
||||
@@ -82,8 +89,8 @@ func ExampleSelectBuilder_advancedUsage() {
|
||||
fmt.Println(args)
|
||||
|
||||
// Output:
|
||||
// SELECT id, name FROM (SELECT * FROM banned WHERE name NOT IN (?, ?)) AS user WHERE status IN (?, ?, ?) AND created_at BETWEEN @start AND @end ORDER BY modified_at DESC
|
||||
// [Huan Du Charmy Liu 1 2 3 {{} start 1234567890} {{} end 1234599999}]
|
||||
// SELECT id, name FROM (SELECT * FROM banned WHERE level > @level AND updated_at <= @end AND name NOT IN (?, ?)) AS user WHERE status IN (?, ?, ?) AND created_at BETWEEN @start AND @end ORDER BY modified_at DESC
|
||||
// [Huan Du Charmy Liu 1 2 3 {{} level 20} {{} end 1234599999} {{} start 1234567890}]
|
||||
}
|
||||
|
||||
func ExampleSelectBuilder_join() {
|
||||
|
||||
@@ -34,6 +34,19 @@ func (sb *stringBuilder) WriteString(s string) {
|
||||
sb.builder.WriteString(s)
|
||||
}
|
||||
|
||||
func (sb *stringBuilder) WriteStrings(ss []string, sep string) {
|
||||
if len(ss) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
sb.WriteString(ss[0])
|
||||
|
||||
for _, s := range ss[1:] {
|
||||
sb.WriteString(sep)
|
||||
sb.WriteString(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *stringBuilder) WriteRune(r rune) {
|
||||
sb.builder.WriteRune(r)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package sqlbuilder
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -162,7 +161,7 @@ func (ub *UnionBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}
|
||||
|
||||
if len(ub.orderByCols) > 0 {
|
||||
buf.WriteLeadingString("ORDER BY ")
|
||||
buf.WriteString(strings.Join(ub.orderByCols, ", "))
|
||||
buf.WriteStrings(ub.orderByCols, ", ")
|
||||
|
||||
if ub.order != "" {
|
||||
buf.WriteRune(' ')
|
||||
|
||||
@@ -6,7 +6,6 @@ package sqlbuilder
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,7 +24,11 @@ func NewUpdateBuilder() *UpdateBuilder {
|
||||
|
||||
func newUpdateBuilder() *UpdateBuilder {
|
||||
args := &Args{}
|
||||
proxy := &whereClauseProxy{}
|
||||
return &UpdateBuilder{
|
||||
whereClauseProxy: proxy,
|
||||
whereClauseExpr: args.Add(proxy),
|
||||
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
@@ -37,11 +40,14 @@ func newUpdateBuilder() *UpdateBuilder {
|
||||
|
||||
// UpdateBuilder is a builder to build UPDATE.
|
||||
type UpdateBuilder struct {
|
||||
*WhereClause
|
||||
Cond
|
||||
|
||||
whereClauseProxy *whereClauseProxy
|
||||
whereClauseExpr string
|
||||
|
||||
table string
|
||||
assignments []string
|
||||
whereExprs []string
|
||||
orderByCols []string
|
||||
order string
|
||||
limit int
|
||||
@@ -82,11 +88,25 @@ func (ub *UpdateBuilder) SetMore(assignment ...string) *UpdateBuilder {
|
||||
|
||||
// Where sets expressions of WHERE in UPDATE.
|
||||
func (ub *UpdateBuilder) Where(andExpr ...string) *UpdateBuilder {
|
||||
ub.whereExprs = append(ub.whereExprs, andExpr...)
|
||||
if ub.WhereClause == nil {
|
||||
ub.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
ub.WhereClause.AddWhereExpr(ub.args, andExpr...)
|
||||
ub.marker = updateMarkerAfterWhere
|
||||
return ub
|
||||
}
|
||||
|
||||
// AddWhereClause adds all clauses in the whereClause to SELECT.
|
||||
func (ub *UpdateBuilder) AddWhereClause(whereClause *WhereClause) *UpdateBuilder {
|
||||
if ub.WhereClause == nil {
|
||||
ub.WhereClause = NewWhereClause()
|
||||
}
|
||||
|
||||
ub.WhereClause.AddWhereClause(whereClause)
|
||||
return ub
|
||||
}
|
||||
|
||||
// Assign represents SET "field = value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Assign(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%s = %s", Escape(field), ub.args.Add(value))
|
||||
@@ -188,20 +208,24 @@ func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
|
||||
|
||||
if len(ub.assignments) > 0 {
|
||||
buf.WriteLeadingString("SET ")
|
||||
buf.WriteString(strings.Join(ub.assignments, ", "))
|
||||
buf.WriteStrings(ub.assignments, ", ")
|
||||
}
|
||||
|
||||
ub.injection.WriteTo(buf, updateMarkerAfterSet)
|
||||
|
||||
if len(ub.whereExprs) > 0 {
|
||||
buf.WriteLeadingString("WHERE ")
|
||||
buf.WriteString(strings.Join(ub.whereExprs, " AND "))
|
||||
if ub.WhereClause != nil {
|
||||
ub.whereClauseProxy.WhereClause = ub.WhereClause
|
||||
defer func() {
|
||||
ub.whereClauseProxy.WhereClause = nil
|
||||
}()
|
||||
|
||||
buf.WriteLeadingString(ub.whereClauseExpr)
|
||||
ub.injection.WriteTo(buf, updateMarkerAfterWhere)
|
||||
}
|
||||
|
||||
if len(ub.orderByCols) > 0 {
|
||||
buf.WriteLeadingString("ORDER BY ")
|
||||
buf.WriteString(strings.Join(ub.orderByCols, ", "))
|
||||
buf.WriteStrings(ub.orderByCols, ", ")
|
||||
|
||||
if ub.order != "" {
|
||||
buf.WriteLeadingString(ub.order)
|
||||
|
||||
+4
-4
@@ -59,10 +59,10 @@ func TestUpdateAssignments(t *testing.T) {
|
||||
cases := map[string]func(ub *UpdateBuilder) string{
|
||||
"f = f + 1|[]": func(ub *UpdateBuilder) string { return ub.Incr("f") },
|
||||
"f = f - 1|[]": func(ub *UpdateBuilder) string { return ub.Decr("f") },
|
||||
"f = f + $0|[123]": func(ub *UpdateBuilder) string { return ub.Add("f", 123) },
|
||||
"f = f - $0|[123]": func(ub *UpdateBuilder) string { return ub.Sub("f", 123) },
|
||||
"f = f * $0|[123]": func(ub *UpdateBuilder) string { return ub.Mul("f", 123) },
|
||||
"f = f / $0|[123]": func(ub *UpdateBuilder) string { return ub.Div("f", 123) },
|
||||
"f = f + $1|[123]": func(ub *UpdateBuilder) string { return ub.Add("f", 123) },
|
||||
"f = f - $1|[123]": func(ub *UpdateBuilder) string { return ub.Sub("f", 123) },
|
||||
"f = f * $1|[123]": func(ub *UpdateBuilder) string { return ub.Mul("f", 123) },
|
||||
"f = f / $1|[123]": func(ub *UpdateBuilder) string { return ub.Div("f", 123) },
|
||||
}
|
||||
|
||||
for expected, f := range cases {
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// Copyright 2018 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
// WhereClause is a Builder for WHERE clause.
|
||||
// All builders which support `WHERE` clause have an anonymous `WhereClause` field,
|
||||
// in which the conditions are stored.
|
||||
//
|
||||
// WhereClause can be shared among multiple builders.
|
||||
// However, it is not thread-safe.
|
||||
type WhereClause struct {
|
||||
flavor Flavor
|
||||
clauses []clause
|
||||
}
|
||||
|
||||
var _ Builder = new(WhereClause)
|
||||
|
||||
// NewWhereClause creates a new WhereClause.
|
||||
func NewWhereClause() *WhereClause {
|
||||
return &WhereClause{}
|
||||
}
|
||||
|
||||
// CopyWhereClause creates a copy of the whereClause.
|
||||
func CopyWhereClause(whereClause *WhereClause) *WhereClause {
|
||||
clauses := make([]clause, len(whereClause.clauses))
|
||||
copy(clauses, whereClause.clauses)
|
||||
|
||||
return &WhereClause{
|
||||
flavor: whereClause.flavor,
|
||||
clauses: clauses,
|
||||
}
|
||||
}
|
||||
|
||||
type clause struct {
|
||||
args *Args
|
||||
andExprs []string
|
||||
}
|
||||
|
||||
func (c *clause) Build(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
|
||||
buf := newStringBuilder()
|
||||
buf.WriteStrings(c.andExprs, " AND ")
|
||||
sql, args = c.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
|
||||
return
|
||||
}
|
||||
|
||||
// whereClauseProxy is a proxy for WhereClause.
|
||||
// It's useful when the WhereClause in a build can be changed.
|
||||
type whereClauseProxy struct {
|
||||
*WhereClause
|
||||
}
|
||||
|
||||
var _ Builder = new(whereClauseProxy)
|
||||
|
||||
// BuildWithFlavor builds a WHERE clause with the specified flavor and initial arguments.
|
||||
func (wc *WhereClause) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
|
||||
if len(wc.clauses) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
buf := newStringBuilder()
|
||||
buf.WriteLeadingString("WHERE ")
|
||||
|
||||
sql, args = wc.clauses[0].Build(flavor, initialArg...)
|
||||
buf.WriteString(sql)
|
||||
|
||||
for _, clause := range wc.clauses[1:] {
|
||||
buf.WriteString(" AND ")
|
||||
sql, args = clause.Build(flavor, args...)
|
||||
buf.WriteString(sql)
|
||||
}
|
||||
|
||||
return buf.String(), args
|
||||
}
|
||||
|
||||
// Build returns compiled WHERE clause string and args.
|
||||
func (wc *WhereClause) Build() (sql string, args []interface{}) {
|
||||
return wc.BuildWithFlavor(wc.flavor)
|
||||
}
|
||||
|
||||
// SetFlavor sets the flavor of compiled sql.
|
||||
// When the WhereClause belongs to a builder, the flavor of the builder will be used when building SQL.
|
||||
func (wc *WhereClause) SetFlavor(flavor Flavor) (old Flavor) {
|
||||
old = wc.flavor
|
||||
wc.flavor = flavor
|
||||
return
|
||||
}
|
||||
|
||||
// AddWhereExpr adds an AND expression to WHERE clause with the specified arguments.
|
||||
func (wc *WhereClause) AddWhereExpr(args *Args, andExpr ...string) {
|
||||
// Merge with last clause if possible.
|
||||
if len(wc.clauses) > 0 {
|
||||
lastClause := &wc.clauses[len(wc.clauses)-1]
|
||||
|
||||
if lastClause.args == args {
|
||||
lastClause.andExprs = append(lastClause.andExprs, andExpr...)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
wc.clauses = append(wc.clauses, clause{
|
||||
args: args,
|
||||
andExprs: andExpr,
|
||||
})
|
||||
}
|
||||
|
||||
// AddWhereClause adds all clauses in the whereClause to the wc.
|
||||
func (wc *WhereClause) AddWhereClause(whereClause *WhereClause) {
|
||||
if whereClause == nil {
|
||||
return
|
||||
}
|
||||
|
||||
wc.clauses = append(wc.clauses, whereClause.clauses...)
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// Copyright 2018 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleWhereClause() {
|
||||
// Build a SQL to select a user from database.
|
||||
sb := Select("name", "level").From("users")
|
||||
sb.Where(
|
||||
sb.Equal("id", 1234),
|
||||
)
|
||||
sql, args := sb.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Query database with the sql and update this user's level...
|
||||
|
||||
ub := Update("users")
|
||||
ub.Set(
|
||||
ub.Add("level", 10),
|
||||
)
|
||||
|
||||
// The WHERE clause of UPDATE should be the same as the WHERE clause of SELECT.
|
||||
ub.WhereClause = sb.WhereClause
|
||||
|
||||
sql, args = ub.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Output:
|
||||
// SELECT name, level FROM users WHERE id = ?
|
||||
// [1234]
|
||||
// UPDATE users SET level = level + ? WHERE id = ?
|
||||
// [10 1234]
|
||||
}
|
||||
|
||||
func ExampleWhereClause_sharedAmongBuilders() {
|
||||
// A WhereClause can be shared among builders.
|
||||
// However, as it's not thread-safe, don't use it in a concurrent environment.
|
||||
sb1 := Select("level").From("users")
|
||||
sb2 := Select("status").From("users")
|
||||
|
||||
// Share the same WhereClause between sb1 and sb2.
|
||||
whereClause := NewWhereClause()
|
||||
sb1.WhereClause = whereClause
|
||||
sb2.WhereClause = whereClause
|
||||
|
||||
// The Where method in sb1 and sb2 will update the same WhereClause.
|
||||
// When we call sb1.Where(), the WHERE clause in sb2 will also be updated.
|
||||
sb1.Where(
|
||||
sb1.Like("name", "Charmy%"),
|
||||
)
|
||||
|
||||
// We can get a copy of the WhereClause.
|
||||
// The copy is independent from the original.
|
||||
sb3 := Select("name").From("users")
|
||||
sb3.WhereClause = CopyWhereClause(whereClause)
|
||||
|
||||
// Adding more expressions to sb1 and sb2 will not affect sb3.
|
||||
sb2.Where(
|
||||
sb2.In("status", 1, 2, 3),
|
||||
)
|
||||
|
||||
// Adding more expressions to sb3 will not affect sb1 and sb2.
|
||||
sb3.Where(
|
||||
sb3.GreaterEqualThan("level", 10),
|
||||
)
|
||||
|
||||
sql1, args1 := sb1.Build()
|
||||
sql2, args2 := sb2.Build()
|
||||
sql3, args3 := sb3.Build()
|
||||
|
||||
fmt.Println(sql1)
|
||||
fmt.Println(args1)
|
||||
fmt.Println(sql2)
|
||||
fmt.Println(args2)
|
||||
fmt.Println(sql3)
|
||||
fmt.Println(args3)
|
||||
|
||||
// Output:
|
||||
// SELECT level FROM users WHERE name LIKE ? AND status IN (?, ?, ?)
|
||||
// [Charmy% 1 2 3]
|
||||
// SELECT status FROM users WHERE name LIKE ? AND status IN (?, ?, ?)
|
||||
// [Charmy% 1 2 3]
|
||||
// SELECT name FROM users WHERE name LIKE ? AND level >= ?
|
||||
// [Charmy% 10]
|
||||
}
|
||||
|
||||
func ExampleWhereClause_clearWhereClause() {
|
||||
db := DeleteFrom("users")
|
||||
db.Where(
|
||||
db.GreaterThan("level", 10),
|
||||
)
|
||||
|
||||
sql, args := db.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Clear WHERE clause.
|
||||
db.WhereClause = nil
|
||||
sql, args = db.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
db.Where(
|
||||
db.Equal("id", 1234),
|
||||
)
|
||||
sql, args = db.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Output:
|
||||
// DELETE FROM users WHERE level > ?
|
||||
// [10]
|
||||
// DELETE FROM users
|
||||
// []
|
||||
// DELETE FROM users WHERE id = ?
|
||||
// [1234]
|
||||
}
|
||||
|
||||
func ExampleWhereClause_AddWhereExpr() {
|
||||
// WhereClause can be used as a standalone builder to build WHERE clause.
|
||||
// It's recommended to use it with Cond.
|
||||
whereClause := NewWhereClause()
|
||||
cond := NewCond()
|
||||
|
||||
whereClause.AddWhereExpr(
|
||||
cond.Args,
|
||||
cond.In("name", "Charmy", "Huan"),
|
||||
cond.LessEqualThan("level", 10),
|
||||
)
|
||||
|
||||
// Set the flavor of the WhereClause to PostgreSQL.
|
||||
whereClause.SetFlavor(PostgreSQL)
|
||||
|
||||
sql, args := whereClause.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Use this WhereClause in another builder.
|
||||
sb := MySQL.NewSelectBuilder()
|
||||
sb.Select("name", "level").From("users")
|
||||
sb.WhereClause = whereClause
|
||||
|
||||
// The flavor of sb overrides the flavor of the WhereClause.
|
||||
sql, args = sb.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Output:
|
||||
// WHERE name IN ($1, $2) AND level <= $3
|
||||
// [Charmy Huan 10]
|
||||
// SELECT name, level FROM users WHERE name IN (?, ?) AND level <= ?
|
||||
// [Charmy Huan 10]
|
||||
}
|
||||
|
||||
func ExampleWhereClause_AddWhereClause() {
|
||||
sb := Select("level").From("users")
|
||||
sb.Where(
|
||||
sb.Equal("id", 1234),
|
||||
)
|
||||
|
||||
sql, args := sb.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
ub := Update("users")
|
||||
ub.Set(
|
||||
ub.Add("level", 10),
|
||||
)
|
||||
|
||||
// Copy the WHERE clause of sb into ub and add more expressions.
|
||||
ub.AddWhereClause(sb.WhereClause).Where(
|
||||
ub.Equal("deleted", 0),
|
||||
)
|
||||
|
||||
sql, args = ub.Build()
|
||||
fmt.Println(sql)
|
||||
fmt.Println(args)
|
||||
|
||||
// Output:
|
||||
// SELECT level FROM users WHERE id = ?
|
||||
// [1234]
|
||||
// UPDATE users SET level = level + ? WHERE id = ? AND deleted = ?
|
||||
// [10 1234 0]
|
||||
}
|
||||
Reference in New Issue
Block a user