mirror of
https://github.com/hanzoai/sqlbuilder.git
synced 2026-10-01 00:37:42 +00:00
init
This commit is contained in:
+35
@@ -0,0 +1,35 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea/
|
||||
|
||||
# VS Code
|
||||
debug
|
||||
debug_test
|
||||
|
||||
# Mac
|
||||
.DS_Store
|
||||
@@ -0,0 +1 @@
|
||||
language: go
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2018 Huan Du
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,6 @@
|
||||
# SQL builder for Go #
|
||||
|
||||
[](https://travis-ci.org/huandu/go-sqlbuilder)
|
||||
[](https://godoc.org/github.com/huandu/go-sqlbuilder)
|
||||
|
||||
TBD
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// Escape replaces `$` with `$$` in ident.
|
||||
func Escape(ident string) string {
|
||||
return strings.Replace(ident, "$", "$$", -1)
|
||||
}
|
||||
|
||||
// EscapeAll replaces `$` with `$$` in all strings of ident.
|
||||
func EscapeAll(ident ...string) []string {
|
||||
escaped := make([]string, 0, len(ident))
|
||||
|
||||
for _, i := range ident {
|
||||
escaped = append(escaped, Escape(i))
|
||||
}
|
||||
|
||||
return escaped
|
||||
}
|
||||
|
||||
// Args stores arguments associated with a SQL.
|
||||
type Args struct {
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// Add adds an arg to Args and returns a placeholder.
|
||||
func (args *Args) Add(arg interface{}) string {
|
||||
idx := len(args.args)
|
||||
args.args = append(args.args, arg)
|
||||
return fmt.Sprintf("$%v", idx)
|
||||
}
|
||||
|
||||
// Compile analyzes builder's sql to standard sql and returns associated args.
|
||||
//
|
||||
// A builder uses `$N` to represent an argument in arguments.
|
||||
// Unescape replaces `$N` to `?`, which is the placeholder supported by SQL driver,
|
||||
// and then creates a new args associated with the placeholder.
|
||||
func (args *Args) Compile(sql string) (query string, values []interface{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
idx := strings.IndexRune(sql, '$')
|
||||
values = make([]interface{}, 0, len(args.args))
|
||||
|
||||
for idx >= 0 {
|
||||
if idx > 0 {
|
||||
buf.WriteString(sql[:idx])
|
||||
}
|
||||
|
||||
sql = sql[:idx+1]
|
||||
|
||||
// Should not happen.
|
||||
if len(sql) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if sql[0] == '$' {
|
||||
buf.WriteRune('$')
|
||||
sql = sql[1:]
|
||||
} else {
|
||||
i := 0
|
||||
|
||||
for ; i < len(sql) && '0' <= sql[i] && sql[i] <= '9'; i++ {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
digits := sql[:i]
|
||||
sql = sql[i:]
|
||||
|
||||
if pointer, err := strconv.Atoi(digits); err == nil && pointer < len(args.args) {
|
||||
buf.WriteRune('?')
|
||||
values = append(values, args.args[pointer])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idx = strings.IndexRune(sql, '$')
|
||||
}
|
||||
|
||||
query = buf.String()
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2018 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cond provides several helper methods to build conditions.
|
||||
type Cond struct {
|
||||
Args *Args
|
||||
}
|
||||
|
||||
// Equal represents "field = value".
|
||||
func (c *Cond) Equal(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v = %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// NotEqual represents "field != value".
|
||||
func (c *Cond) NotEqual(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v != %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// GreaterThan represents "field > value".
|
||||
func (c *Cond) GreaterThan(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v > %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// G is an alias of GreaterThan.
|
||||
func (c *Cond) G(field string, value interface{}) string {
|
||||
return c.GreaterThan(field, value)
|
||||
}
|
||||
|
||||
// GreaterEqualThan represents "field >= value".
|
||||
func (c *Cond) GreaterEqualThan(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v >= %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// GE is an alias of GreaterEqualThan.
|
||||
func (c *Cond) GE(field string, value interface{}) string {
|
||||
return c.GreaterEqualThan(field, value)
|
||||
}
|
||||
|
||||
// LessThan represents "field < value".
|
||||
func (c *Cond) LessThan(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v < %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// L is an alias of LessThan.
|
||||
func (c *Cond) L(field string, value interface{}) string {
|
||||
return c.LessThan(field, value)
|
||||
}
|
||||
|
||||
// LessEqualThan represents "field <= value".
|
||||
func (c *Cond) LessEqualThan(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v != %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// LE is an alias of LessEqualThan.
|
||||
func (c *Cond) LE(field string, value interface{}) string {
|
||||
return c.LessEqualThan(field, value)
|
||||
}
|
||||
|
||||
// In represents "field IN (value...)".
|
||||
func (c *Cond) In(field string, value ...interface{}) string {
|
||||
vs := make([]string, 0, len(value))
|
||||
|
||||
for _, v := range value {
|
||||
vs = append(vs, c.Args.Add(v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v IN (%v)", Escape(field), strings.Join(vs, ", "))
|
||||
}
|
||||
|
||||
// NotIn represents "field NOT IN (value...)".
|
||||
func (c *Cond) NotIn(field string, value ...interface{}) string {
|
||||
vs := make([]string, 0, len(value))
|
||||
|
||||
for _, v := range value {
|
||||
vs = append(vs, c.Args.Add(v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v NOT IN (%v)", Escape(field), strings.Join(vs, ", "))
|
||||
}
|
||||
|
||||
// Like represents "field LIKE value".
|
||||
func (c *Cond) Like(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v LIKE %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// NotLike represents "field NOT LIKE value".
|
||||
func (c *Cond) NotLike(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v NOT LIKE %v", Escape(field), c.Args.Add(value))
|
||||
}
|
||||
|
||||
// IsNull represents "field IS NULL".
|
||||
func (c *Cond) IsNull(field string) string {
|
||||
return fmt.Sprintf("%v IS NULL", Escape(field))
|
||||
}
|
||||
|
||||
// IsNotNull represents "field IS NOT NULL".
|
||||
func (c *Cond) IsNotNull(field string) string {
|
||||
return fmt.Sprintf("%v IS NOT NULL", Escape(field))
|
||||
}
|
||||
|
||||
// Between represents "field BETWEEN lower AND upper".
|
||||
func (c *Cond) Between(field string, lower, upper interface{}) string {
|
||||
return fmt.Sprintf("%v BETWEEN %v AND %v", Escape(field), c.Args.Add(lower), c.Args.Add(upper))
|
||||
}
|
||||
|
||||
// Var returns a placeholder for value.
|
||||
func (c *Cond) Var(value interface{}) string {
|
||||
return c.Args.Add(value)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2018 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewDeleteBuilder creates a new DELETE builder.
|
||||
func NewDeleteBuilder() *DeleteBuilder {
|
||||
args := &Args{}
|
||||
return &DeleteBuilder{
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteBuilder is a builder to build DELETE.
|
||||
//
|
||||
// Usage:
|
||||
// db := NewDeleteBuilder()
|
||||
// db.DeleteFrom("demo.user")
|
||||
// .Where(
|
||||
// db.GreaterThan("id", 1234),
|
||||
// db.Like("name", "%Du"),
|
||||
// db.Or(
|
||||
// db.IsNull("id_card"),
|
||||
// db.In("status", 1, 2, 5),
|
||||
// ),
|
||||
// "modified_at > created_at + " + db.Var(86400), // It's allowed to write arbitrary SQL.
|
||||
// )
|
||||
// sql, args := db.Build()
|
||||
// fmt.Println(sql)
|
||||
// fmt.Println(args)
|
||||
//
|
||||
// // Output:
|
||||
// // DELETE FROM demo.user WHERE id > ? AND name LIKE ? AND (id_card IS NULL OR status IN (?, ?, ?)) AND modified_at > created_at + ?
|
||||
// // [1234, %Du, 1, 2, 5, 86400]
|
||||
type DeleteBuilder struct {
|
||||
Cond
|
||||
|
||||
table string
|
||||
whereExprs []string
|
||||
|
||||
args *Args
|
||||
}
|
||||
|
||||
// DeleteFrom sets table name in DELETE.
|
||||
func (db *DeleteBuilder) DeleteFrom(table string) *DeleteBuilder {
|
||||
db.table = Escape(table)
|
||||
return db
|
||||
}
|
||||
|
||||
// Where sets expressions of WHERE in UPDATE.
|
||||
func (db *DeleteBuilder) Where(andExpr ...string) *DeleteBuilder {
|
||||
db.whereExprs = append(db.whereExprs, andExpr...)
|
||||
return db
|
||||
}
|
||||
|
||||
// String returns the compiled UPDATE string.
|
||||
func (db *DeleteBuilder) String() string {
|
||||
s, _ := db.Build()
|
||||
return s
|
||||
}
|
||||
|
||||
// Build returns compiled DELETE string and args.
|
||||
// They can be used in `DB#Query` of package `database/sql` directly.
|
||||
func (db *DeleteBuilder) Build() (sql string, args []interface{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString("DELETE FROM ")
|
||||
buf.WriteString(db.table)
|
||||
|
||||
if len(db.whereExprs) > 0 {
|
||||
buf.WriteString(" WHERE ")
|
||||
buf.WriteString(strings.Join(db.whereExprs, " AND "))
|
||||
}
|
||||
|
||||
return db.args.Compile(buf.String())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2018 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
// Package sqlbuilder is a flexible and powerful tool to build SQL string and associated args.
|
||||
package sqlbuilder
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewInsertBuilder creates a new INSERT builder.
|
||||
func NewInsertBuilder() *InsertBuilder {
|
||||
args := &Args{}
|
||||
return &InsertBuilder{
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
// InsertBuilder is a builder to build INSERT.
|
||||
//
|
||||
// Usage:
|
||||
// ib := NewInsertBuilder()
|
||||
// ib.InsertInto("demo.user")
|
||||
// .Cols("id", "name", "status", "created_at")
|
||||
// .Values(1, "Huan Du", 1, ib.Raw("UNIX_TIMESTAMP(NOW())"))
|
||||
// .Values(2, "Charmy Liu", 1, 1234567890)
|
||||
// sql, args := ib.Build()
|
||||
// fmt.Println(sql)
|
||||
// fmt.Println(args)
|
||||
//
|
||||
// // Output:
|
||||
// // INSERT INTO demo.user (id, name, status, creasted_at) VALEUS (?, ?, ?, ?), (?, ?, ?, ?)
|
||||
// // [1, Huan Du, 1, 2, Charmy Liu, 1, 1234567890]
|
||||
type InsertBuilder struct {
|
||||
table string
|
||||
cols []string
|
||||
values [][]string
|
||||
|
||||
args *Args
|
||||
}
|
||||
|
||||
// InsertInto sets table name in INSERT.
|
||||
func (ib *InsertBuilder) InsertInto(table string) *InsertBuilder {
|
||||
ib.table = Escape(table)
|
||||
return ib
|
||||
}
|
||||
|
||||
// Cols sets columns in INSERT.
|
||||
func (ib *InsertBuilder) Cols(col ...string) *InsertBuilder {
|
||||
ib.cols = EscapeAll(col...)
|
||||
return ib
|
||||
}
|
||||
|
||||
// Values adds a list of values for a row in INSERT.
|
||||
func (ib *InsertBuilder) Values(value ...interface{}) *InsertBuilder {
|
||||
placeholders := make([]string, 0, len(value))
|
||||
|
||||
for _, v := range value {
|
||||
placeholders = append(placeholders, ib.args.Add(v))
|
||||
}
|
||||
|
||||
ib.values = append(ib.values, placeholders)
|
||||
return ib
|
||||
}
|
||||
|
||||
// String returns the compiled UPDATE string.
|
||||
func (ib *InsertBuilder) String() string {
|
||||
s, _ := ib.Build()
|
||||
return s
|
||||
}
|
||||
|
||||
// Build returns compiled INSERT string and args.
|
||||
// They can be used in `DB#Query` of package `database/sql` directly.
|
||||
func (ib *InsertBuilder) Build() (sql string, args []interface{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString("INSERT INTO ")
|
||||
buf.WriteString(ib.table)
|
||||
|
||||
if len(ib.cols) > 0 {
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(strings.Join(ib.cols, ", "))
|
||||
buf.WriteString(")")
|
||||
}
|
||||
|
||||
buf.WriteString(" VALUES ")
|
||||
values := make([]string, 0, len(ib.values))
|
||||
|
||||
for _, v := range ib.values {
|
||||
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
|
||||
}
|
||||
|
||||
buf.WriteString(strings.Join(values, ", "))
|
||||
return ib.args.Compile(buf.String())
|
||||
}
|
||||
@@ -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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewSelectBuilder creates a new SELECT builder.
|
||||
func NewSelectBuilder() *SelectBuilder {
|
||||
args := &Args{}
|
||||
return &SelectBuilder{
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
limit: -1,
|
||||
offset: -1,
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
// SelectBuilder is a builder to build SELECT.
|
||||
//
|
||||
// Usage:
|
||||
// sb := NewSelectBuilder()
|
||||
// sb.Distinct().Select("id", "name", sb.As("COUNT(*)", "t"))
|
||||
// .From("demo.user")
|
||||
// .Where(
|
||||
// sb.GreaterThan("id", 1234),
|
||||
// sb.Like("name", "%Du"),
|
||||
// sb.Or(
|
||||
// sb.IsNull("id_card"),
|
||||
// sb.In("status", 1, 2, 5),
|
||||
// ),
|
||||
// "modified_at > created_at + " + sb.Var(86400), // It's allowed to write arbitrary SQL.
|
||||
// )
|
||||
// .GroupBy("status").Having(sb.NotIn("status", 4, 5))
|
||||
// .OrderBy("modified_at").Asc()
|
||||
// .Limit(10).Offset(5)
|
||||
// sql, args := sb.Build()
|
||||
// fmt.Println(sql)
|
||||
// fmt.Println(args)
|
||||
//
|
||||
// // Output:
|
||||
// // SELECT id, name, COUNT(*) AS t FROM demo.user WHERE id > ? AND name LIKE ? AND (id_card IS NULL OR status IN (?, ?, ?)) AND modified_at > created_at + ? GROUP BY status HAVING status NOT IN (4, 5) ORDER BY modified_at ASC LIMIT 10 OFFSET 5
|
||||
// // [t, 1234, %Du, 1, 2, 5, 86400]
|
||||
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 = EscapeAll(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 expreesion.
|
||||
func (sb *SelectBuilder) As(col, alias string) string {
|
||||
return fmt.Sprintf("%v AS %v", Escape(col), 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{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString("SELECT ")
|
||||
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.Compile(buf.String())
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// 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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewUpdateBuilder creates a new UPDATE builder.
|
||||
func NewUpdateBuilder() *UpdateBuilder {
|
||||
args := &Args{}
|
||||
return &UpdateBuilder{
|
||||
Cond: Cond{
|
||||
Args: args,
|
||||
},
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateBuilder is a builder to build UPDATE.
|
||||
//
|
||||
// Usage:
|
||||
// ub := NewUpdateBuilder()
|
||||
// ub.Update("demo.user")
|
||||
// .Set(
|
||||
// ub.Assign("type", "sys"),
|
||||
// ub.Incr("credit"),
|
||||
// "modified_at = UNIX_TIMESTAMP(NOW())", // It's allowed to write arbitrary SQL.
|
||||
// )
|
||||
// .Where(
|
||||
// ub.GreaterThan("id", 1234),
|
||||
// ub.Like("name", "%Du"),
|
||||
// ub.Or(
|
||||
// ub.IsNull("id_card"),
|
||||
// ub.In("status", 1, 2, 5),
|
||||
// ),
|
||||
// "modified_at > created_at + " + ub.Var(86400), // It's allowed to write arbitrary SQL.
|
||||
// )
|
||||
// sql, args := ub.Build()
|
||||
// fmt.Println(sql)
|
||||
// fmt.Println(args)
|
||||
//
|
||||
// // Output:
|
||||
// // UPDATE demo.user SET type = ?, credit = credit + 1, modified_at = UNIX_TIMESTAMP(NOW()) WHERE id > ? AND name LIKE ? AND (id_card IS NULL OR status IN (?, ?, ?)) AND modified_at > created_at + ?
|
||||
// // [sys, 1234, %Du, 1, 2, 5, 86400]
|
||||
type UpdateBuilder struct {
|
||||
Cond
|
||||
|
||||
table string
|
||||
assignments []string
|
||||
whereExprs []string
|
||||
|
||||
args *Args
|
||||
}
|
||||
|
||||
// Update sets table name in UPDATE.
|
||||
func (ub *UpdateBuilder) Update(table string) *UpdateBuilder {
|
||||
ub.table = Escape(table)
|
||||
return ub
|
||||
}
|
||||
|
||||
// Set sets the assignements in SET.
|
||||
func (ub *UpdateBuilder) Set(assignment ...string) *UpdateBuilder {
|
||||
ub.assignments = assignment
|
||||
return ub
|
||||
}
|
||||
|
||||
// Where sets expressions of WHERE in UPDATE.
|
||||
func (ub *UpdateBuilder) Where(andExpr ...string) *UpdateBuilder {
|
||||
ub.whereExprs = append(ub.whereExprs, andExpr...)
|
||||
return ub
|
||||
}
|
||||
|
||||
// Assign represents SET "field = value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Assign(field string, value interface{}) string {
|
||||
return fmt.Sprintf("%v = %v", Escape(field), ub.args.Add(value))
|
||||
}
|
||||
|
||||
// Incr represents SET "field = field + 1" in UPDATE.
|
||||
func (ub *UpdateBuilder) Incr(field string) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v + 1", f, f)
|
||||
}
|
||||
|
||||
// Decr represents SET "field = field - 1" in UPDATE.
|
||||
func (ub *UpdateBuilder) Decr(field string) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v - 1", f, f)
|
||||
}
|
||||
|
||||
// Add represents SET "field = field + value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Add(field string, value interface{}) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v + %v", f, f, ub.args.Add(value))
|
||||
}
|
||||
|
||||
// Sub represents SET "field = field - value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Sub(field string, value interface{}) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v - %v", f, f, ub.args.Add(value))
|
||||
}
|
||||
|
||||
// Mul represents SET "field = field * value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Mul(field string, value interface{}) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v * %v", f, f, ub.args.Add(value))
|
||||
}
|
||||
|
||||
// Div represents SET "field = field / value" in UPDATE.
|
||||
func (ub *UpdateBuilder) Div(field string, value interface{}) string {
|
||||
f := Escape(field)
|
||||
return fmt.Sprintf("%v = %v / %v", f, f, ub.args.Add(value))
|
||||
}
|
||||
|
||||
// String returns the compiled UPDATE string.
|
||||
func (ub *UpdateBuilder) String() string {
|
||||
s, _ := ub.Build()
|
||||
return s
|
||||
}
|
||||
|
||||
// Build returns compiled UPDATE string and args.
|
||||
// They can be used in `DB#Query` of package `database/sql` directly.
|
||||
func (ub *UpdateBuilder) Build() (sql string, args []interface{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString("UPDATE ")
|
||||
buf.WriteString(ub.table)
|
||||
buf.WriteString(" SET ")
|
||||
buf.WriteString(strings.Join(ub.assignments, ", "))
|
||||
|
||||
if len(ub.whereExprs) > 0 {
|
||||
buf.WriteString(" WHERE ")
|
||||
buf.WriteString(strings.Join(ub.whereExprs, " AND "))
|
||||
}
|
||||
|
||||
return ub.args.Compile(buf.String())
|
||||
}
|
||||
Reference in New Issue
Block a user