package obreron
// DeleteStm represents a DELETE SQL statement builder.
// It provides a fluent interface for constructing DELETE queries.
type DeleteStm struct {
*stament
}
func Delete() *DeleteStm {
d := &DeleteStm{
stament: pool.Get().(*stament),
}
d.add(deleteS, "DELETE", "")
return d
}
// From sets the target table for the delete stament
//
// # Example
//
// s := Delete()
// From("client")
func (dst *DeleteStm) From(source string) *DeleteStm {
dst.add(fromS, "FROM", source)
return dst
}
// Where adds a condition to filter the query
func (dst *DeleteStm) Where(cond string, p ...any) *DeleteStm {
dst.where(cond, p...)
return dst
}
// Y adds an AND conector to the stament where is called. Its helpful when used with In()
func (dst *DeleteStm) Y() *DeleteStm {
dst.clause("AND", "")
return dst
}
// And adds a condition to the query connecting with an AND operator
func (dst *DeleteStm) And(expr string, p ...any) *DeleteStm {
dst.clause("AND", expr, p...)
return dst
}
// AndIf adds a condition to the query connecting with an AND operator only when cond parameter is true
func (dst *DeleteStm) AndIf(cond bool, expr string, p ...any) *DeleteStm {
if cond {
dst.clause("AND", expr, p...)
}
return dst
}
func (dst *DeleteStm) Or(expr string, p ...any) *DeleteStm {
dst.clause("OR", expr, p...)
return dst
}
func (dst *DeleteStm) OrIf(cond bool, expr string, p ...any) *DeleteStm {
if cond {
dst.clause("OR", expr, p...)
}
return dst
}
// Like adds a LIKE clause to the query after the las clause added
func (dst *DeleteStm) Like(expr string, p ...any) *DeleteStm {
dst.clause("LIKE", expr, p...)
return dst
}
// LikeIf adds a LIKE clause to the query after the las clause added, when cond is true
func (dst *DeleteStm) LikeIf(cond bool, expr string, p ...any) *DeleteStm {
if cond {
dst.Like(expr, p...)
}
return dst
}
// In adds a IN clause to the query after the las clause added
func (dst *DeleteStm) In(value, expr string, p ...any) *DeleteStm {
dst.clause(value+" IN ("+expr+")", "", p...)
return dst
}
// InArgs adds an IN clause to the statement with automatically generated positional parameters.
// Example:
//
// Delete().From("users").Where("active = ?", true).InArgs("id", 1, 2, 3)
//
// Generates: DELETE FROM users WHERE active = ? AND id IN (?, ?, ?)
func (dst *DeleteStm) InArgs(value string, p ...any) *DeleteStm {
dst.stament.inArgs(value, p...)
return dst
}
// Close releases the statement back to the pool.
// After calling Close, the statement should not be used.
func (dst *DeleteStm) Close() {
CloseStament(dst.stament)
}
func (dst *DeleteStm) OrderBy(expr string, p ...any) *DeleteStm {
dst.add(limitS, "ORDER BY", expr, p...)
return dst
}
// Limit adds a LIMIT clause to the query
func (dst *DeleteStm) Limit(limit int) *DeleteStm {
dst.add(limitS, "LIMIT", "?", limit)
return dst
}
// Clause adds a custom clause to the query in the position were is invoked
func (dst *DeleteStm) Clause(clause, expr string, p ...any) *DeleteStm {
dst.add(dst.lastPos, clause, expr, p...)
return dst
}
func (dst *DeleteStm) ClauseIf(cond bool, clause, expr string, p ...any) *DeleteStm {
if cond {
dst.Clause(clause, expr, p...)
}
return dst
}
package main
import (
"fmt"
v2 "github.com/profe-ajedrez/obreron/v2"
)
func main() {
// Simple delete
fmt.Println("Simple Delete")
q, p := v2.Delete().From("client").Build()
fmt.Printf("query: %s \nparams: %v\n\n", q, p)
// OUTPUT:
// query: DELETE FROM client
// params: []
// Delete with conditions
fmt.Println("Delete With conditions")
q, p = v2.Delete().From("client").
Where("client_id = 100").
And("estado_cliente = 0").
Y().In("regime_cliente", "'G01','G02', ?", "'G03'").
And("a").
Build()
fmt.Printf("query: %s \nparams: %v\n\n", q, p)
// OUTPUT:
// query: DELETE FROM client WHERE client_id = 100 AND estado_cliente = 0 AND regime_cliente IN ('G01','G02', ?) AND a
// params: ['G03']
}
package main
import (
"fmt"
v2 "github.com/profe-ajedrez/obreron/v2"
)
func main() {
// Simple Insert
fmt.Println("Simple Insert")
q, p := v2.Insert().
Into("client").
Col("name, mail", "some name", "somemail@mail.net").
Build()
fmt.Printf("query: %s \nparams: %v\n\n", q, p)
// OUTPUT:
// qquery: INSERT INTO client ( name, mail ) VALUES ( ?,? )
// nparams: [some name somemail@mail.net]
// Conditional insert
fmt.Println("Conditional Insert")
name := ""
mail := "somemail@mail.net"
q, p = v2.Insert().
Into("client").
ColIf(len(name) > 0, "name", name).
ColIf(len(mail) > 0, "mail", mail).
Build()
fmt.Printf("query: %s \nparams: %v\n\n", q, p)
// OUTPUT:
// query: INSERT INTO client ( mail ) VALUES ( ? )
// params: [somemail@mail.net]
// Insert Select
fmt.Println("Insert Select")
q, p = v2.Insert().
Into("courses").
ColSelect("name, location, gid",
v2.Select().
Col("name, location, 1").
From("courses").
Where("cid = 2"),
).Build()
fmt.Printf("query: %s \nparams: %v\n", q, p)
// OUTPUT
// query: INSERT INTO courses ( name, location, gid ) SELECT name, location, 1 FROM courses WHERE cid = 2
// params: []
}
package obreron
import (
"bytes"
"slices"
"strings"
"unsafe"
)
// InsertStament represents an insert stament
type InsertStament struct {
*stament
withSelect bool
}
// Insert Returns an insert stament
//
// # Example
//
// ins := Insert().Into("client").Col("name", "'some name'").Col("value", "'somemail@mail.net'").ColIf(true, "data", "'some data'").ColIf(false, "info", 12)
//
// query, p := ins.Build()
//
// r, err := db.Exec(q, p...)
func Insert() *InsertStament {
i := &InsertStament{pool.Get().(*stament), false}
i.add(insertS, "INSERT", "")
i.firstCol = true
return i
}
// Ignore adds Ignore clause to the insert stament
//
// # Example
//
// ins := Insert().Ignore().Into("client").Col("name, value", "'some name'", "'somemail@mail.net'")
//
// query, p := ins.Build()
//
// r, err := db.Exec(q, p...)
func (in *InsertStament) Ignore() *InsertStament {
in.add(insertS, "IGNORE", "")
return in
}
// Into adds into clause to the insert stament
func (in *InsertStament) Into(table string) *InsertStament {
in.add(insertS, "INTO", table)
return in
}
// Col adds columns and values to the insert clause
//
// # Example
//
// ins := insInsert().Col("name, value", "'some name'", "'somemail@mail.net'").Into("client")
//
// query, p := ins.Build()
//
// r, err := db.Exec(q, p...)
func (in *InsertStament) Col(col string, p ...any) *InsertStament {
if !in.firstCol {
in.Clause(",", "")
in.add(colsS, col, "")
in.add(insP, "", strings.Repeat("?", len(p)), p...)
} else {
in.firstCol = false
in.add(colsS, "(", col)
pp := ""
if l := len(p); l >= 1 {
pp = strings.Repeat("?,", len(p)-1)
}
pp += "?"
spp := unsafe.Slice(unsafe.StringData(pp), len(pp))
spp = spp[:]
pp = *(*string)(unsafe.Pointer(&spp))
in.add(insP, "", pp, p...)
}
return in
}
// ColIf adds columns and values to the insert clause when the cond parameter is true
//
// # Example
//
// ins := insInsert().ColIf(true, "name, value", "'some name'", "'somemail@mail.net'").Into("client")
//
// query, p := ins.Build()
//
// r, err := db.Exec(q, p...)
func (in *InsertStament) ColIf(cond bool, col string, p ...any) *InsertStament {
if cond {
return in.Col(col, p...)
}
return in
}
// ColSelect is a helper method used to build insert select... staments
//
// # Example
//
// ins := Insert().Into("courses").ColSelectIf(true, "name, location, gid", Select().Col("name, location, 1").From("courses").Where("cid = 2")).ColSelectIf(false, "last_name, last_location, grid", Select().Col("last_name, last_location, 11").From("courses").Where("cid = 2"))
//
// query, p := ins.Build()
//
// r, err := db.Exec(q, p...)
//
// Produces: INSERT INTO courses ( name, location, gid ) SELECT name, location, 1 FROM courses WHERE cid = 2
func (in *InsertStament) ColSelect(col string, expr *SelectStm) *InsertStament {
in.firstCol = true
in.add(colsS, "(", col)
q, pp := expr.Build()
in.add(insP, "", q, pp...)
in.withSelect = true
return in
}
func (in *InsertStament) ColSelectIf(cond bool, col string, expr *SelectStm) *InsertStament {
if cond {
return in.ColSelect(col, expr)
}
return in
}
func (in *InsertStament) Clause(clause, expr string, p ...any) *InsertStament {
in.add(in.lastPos, clause, expr, p...)
return in
}
// Build returns the query and the parameters as to be used by *sql.DB.query or *sql.DB.Exec
func (in *InsertStament) Build() (string, []any) {
b := bytes.Buffer{}
if in.withSelect {
b.Grow(in.buff.Len() + 2)
} else {
b.Grow(in.buff.Len() + 10)
}
buf := in.buff.Bytes()
slices.SortStableFunc(in.s, func(a, b segment) int {
if a.sType < b.sType {
return -1
}
if a.sType > b.sType {
return +1
}
if a.sType == insP {
return -1
}
return 0
})
i := posClauses(in, &b, buf)
if in.withSelect {
b.WriteString(") ")
} else {
b.WriteString(") VALUES ( ")
}
posParams(i, in, &b, buf)
if !in.withSelect {
b.WriteString(" )")
}
ss := b.Bytes()
return *(*string)(unsafe.Pointer(&ss)), in.p
}
func posClauses(in *InsertStament, b *bytes.Buffer, buf []byte) int {
i := 0
for i < len(in.s) && in.s[i].sType != insP {
k := i
j := 0
for k < len(in.s) && in.s[k].sType == in.s[i].sType {
if j > 0 && j < len(in.s)-1 {
if in.s[i].sType != colsS {
b.WriteString(" ")
} else {
b.WriteString(", ")
}
}
b.Write(buf[in.s[k].start : in.s[k].start+in.s[k].length])
k++
j++
}
i = k - 1
if i < len(in.s)-1 {
b.WriteString(" ")
}
i++
}
return i
}
func posParams(i int, in *InsertStament, b *bytes.Buffer, buf []byte) {
for i < len(in.s) {
k := i
for k < len(in.s) && in.s[k].sType == in.s[i].sType {
b.Write(buf[in.s[k].start : in.s[k].start+in.s[k].length])
k++
}
i = k - 1
i++
}
}
// Close free resources used by the stament
func (in *InsertStament) Close() {
CloseStament(in.stament)
}
package obreron
import (
"bytes"
"slices"
"strings"
"sync"
"unsafe"
)
var pool = &sync.Pool{
New: func() interface{} {
return &stament{grouped: false, firstCol: true}
},
}
func CloseStament(st *stament) {
if st == nil {
return
}
for i := range st.p {
st.p[i] = nil
}
st.p = make([]any, 0)
st.s = make([]segment, 0)
st.lastPos = 0
st.grouped = false
st.firstCol = true
st.whereAdded = false
st.buff.Reset()
pool.Put(st)
}
type segment struct {
start, length, pCount, pIndex, sType int
}
type stament struct {
s []segment
p []any
buff bytes.Buffer
lastPos int
whereAdded bool
grouped bool
firstCol bool
}
func (st *stament) clause(clause, expr string, p ...any) {
st.add(st.lastPos, clause, expr, p...)
}
func (st *stament) inArgs(value string, p ...any) {
if len(p) == 0 {
st.clause(value+" IN ()", "")
return
}
if len(p) == 1 {
st.clause(value+" IN (?)", "", p...)
return
}
l := len(p)
var builder strings.Builder
builder.Grow(l * 2) // Pre-allocate capacity, fool!
builder.WriteString("?")
for i := 1; i < l; i++ {
builder.WriteString(", ?")
}
st.clause(value+" IN ("+builder.String()+")", "", p...)
}
func (st *stament) where(cond string, p ...any) {
if !st.whereAdded {
st.add(whereS, "WHERE", cond, p...)
st.whereAdded = true
} else {
st.add(whereS, "AND", cond, p...)
}
}
// Build return the query as a string with the added parameters
func (st *stament) Build() (string, []any) {
b := bytes.Buffer{}
b.Grow(st.buff.Len())
buf := st.buff.Bytes()
slices.SortStableFunc(st.s, func(a, b segment) int {
if a.sType < b.sType {
return -1
}
if a.sType > b.sType {
return +1
}
return 0
})
dest := orderQueryAndParams(st, &b, buf)
ss := b.Bytes()
return *(*string)(unsafe.Pointer(&ss)), dest
}
func orderQueryAndParams(st *stament, b *bytes.Buffer, buf []byte) []any {
dest := make([]any, len(st.p))
first := 0
for i := 0; i < len(st.s); i++ {
k := i
j := 0
for k < len(st.s) && st.s[k].sType == st.s[i].sType {
if j > 0 && j < len(st.s)-1 && st.s[i].sType != colsS {
b.WriteString(" ")
}
b.Write(buf[st.s[k].start : st.s[k].start+st.s[k].length])
if st.s[k].pIndex > -1 {
copy(dest[first:], st.p[st.s[k].pIndex:st.s[k].pIndex+st.s[k].pCount])
first += st.s[k].pCount
}
k++
j++
}
i = k - 1
if i < len(st.s)-1 {
b.WriteString(" ")
}
}
return dest
}
func (st *stament) add(pos int, clause, expr string, p ...any) {
pl := len(p)
start := st.buff.Len()
// Remember last clause added, to be used when method Clause is invoked
st.lastPos = pos
if cap(st.s) == len(st.s) {
segments := make([]segment, len(st.s), cap(st.s)*2)
copy(segments, st.s)
st.s = segments
}
l := len(clause)
_, _ = st.buff.WriteString(clause)
if expr != "" {
if l > 0 {
_, _ = st.buff.WriteString(" ")
l += 1
}
_, _ = st.buff.WriteString(expr)
l += len(expr)
}
st.s = append(st.s, segment{
start: start,
length: l,
pCount: pl,
pIndex: -1,
sType: pos,
})
if pl > 0 {
st.s[len(st.s)-1].pIndex = len(st.p)
st.p = append(st.p, p...)
//st.p = insertAt(st.p, p, len(st.p))
}
}
const (
selectS = 0
deleteS = 0
updateS = 0
insertS = 0
colsS = 1
setS = 1
fromS = 2
valueS = 2
joinS = 3
whereS = 4
groupS = 5
havingS = 6
orderS = 7
limitS = 8
offsetS = 9
insP = 99
)
// Package obreron provides a simple, fast and cheap query builder
package obreron
// SelectStm is a select stament
type SelectStm struct {
*stament
}
func CloseSelect(s *SelectStm) {
CloseStament(s.stament)
}
// Select Returns a select stament
//
// # Example
//
// query, _ := Select().Col("a1, a2, a3").From("client").Build()
// r, error := db.Query(q)
func Select() *SelectStm {
s := &SelectStm{
pool.Get().(*stament),
}
s.add(selectS, "SELECT", "")
return s
}
// Close release the resources used by the stament
func (st *SelectStm) Close() {
CloseStament(st.stament)
}
// Col adds a column to the select stament.
//
// # Example
//
// s := Select()
// s.Col("name, mail").Col("? AS max_credit", 1000000).
// From("client")
func (st *SelectStm) Col(expr string, p ...any) *SelectStm {
if !st.firstCol {
st.add(colsS, ",", expr, p...)
return st
}
st.add(colsS, "", expr, p...)
st.firstCol = false
return st
}
// ColIf adds a column to the select stament only when `cond` parameter is true.
//
// # Example
//
// addMaxCredit := true
//
// s := Select()
// s.Col("name, mail").ColIf(addMaxCredit, "? AS max_credit", 1000000).
// From("client")
func (st *SelectStm) ColIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
if !st.firstCol {
st.add(colsS, ",", expr, p...)
return st
}
st.firstCol = false
st.add(colsS, "", expr, p...)
}
return st
}
// From sets the source table for the select stament
//
// # Example
//
// s := Select()
// s.Col("*").
// From("client")
func (st *SelectStm) From(source string) *SelectStm {
st.add(fromS, "FROM", source)
return st
}
// Join adds a relation to the query in the form of an inner join
//
// # Example
//
// s := Select().Col("*").From("client").
// Join("addresses a ON a.client_id = c.client_id")
//
// # Also On clause can be used along with connectors and parameters
//
// s := Select().Col("*").From("client").
// Join("addresses a").On("a.client_id = c.client_id").And("c.status = ?", 0)
func (st *SelectStm) Join(expr string, p ...any) *SelectStm {
st.add(joinS, "JOIN", expr, p...)
return st
}
// JoinIf adds a relation to the query in the form of an inner join only when the cond parameter is true
//
// # Example
//
// addJoin := true
// s := Select().Col("*").
// From("client").
// JoinIf(addJoin, "addresses a ON a.client_id = c.client_id")
//
// # Also OnIf clause can be used along with connectors and parameters
//
// s := Select().Col("*").
// From("client").
// JoinIf(aaddJoin, "addresses a").
// OnIf(addJoin, "a.client_id = c.client_id").And("c.status = ?", 0)
func (st *SelectStm) JoinIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.add(joinS, "JOIN", expr, p...)
}
return st
}
// LeftJoin adds a relation to the query in the form of a left join
//
// # Example
//
// s := Select().Col("*").From("client").
// LeftJoin("addresses a ON a.client_id = c.client_id")
//
// # Also On clause can be used along with connectors and parameters
//
// s := Select().Col("*").From("client").
// LeftJoin("addresses a").On("a.client_id = c.client_id").And("c.status = ?", 0)
func (st *SelectStm) LeftJoin(expr string, p ...any) *SelectStm {
st.add(joinS, "LEFT JOIN", expr, p...)
return st
}
// LeftJoinIf adds a relation to the query in the form of a left join only when the cond parameter is true
//
// # Example
//
// addJoin := true
// s := Select().Col("*").
// From("client").
// LeftJoinIf(addJoin, "addresses a ON a.client_id = c.client_id")
//
// # Also OnIf clause can be used along with connectors and parameters
//
// s := Select().Col("*").
// From("client").
// LeftJoinIf(aaddJoin, "addresses a").
// OnIf(addJoin, "a.client_id = c.client_id").And("c.status = ?", 0)
func (st *SelectStm) LeftJoinIf(cond bool, join string, p ...any) *SelectStm {
if cond {
st.add(joinS, "LEFT JOIN", join, p...)
}
return st
}
func (st *SelectStm) RightJoin(expr string, p ...any) *SelectStm {
st.add(joinS, "RIGHT JOIN", expr, p...)
return st
}
func (st *SelectStm) RightJoinIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.add(joinS, "RIGHT JOIN", expr, p...)
}
return st
}
func (st *SelectStm) OuterJoin(expr string, p ...any) *SelectStm {
st.add(joinS, "OUTER JOIN", expr, p...)
return st
}
func (st *SelectStm) OuterJoinIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.add(joinS, "OUTER JOIN", expr, p...)
}
return st
}
func (st *SelectStm) On(on string, p ...any) *SelectStm {
st.clause("ON", on, p...)
return st
}
func (st *SelectStm) OnIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.clause("ON", expr, p...)
}
return st
}
// Where adds a condition to filter the query
//
// # Example
//
// s := Select().Col("*").From("client").
// Where("status = ?", 1)
func (st *SelectStm) Where(cond string, p ...any) *SelectStm {
st.where(cond, p...)
return st
}
// And adds a condition to the query connecting with an AND operator
//
// # Example
//
// s := Select().Col("*").From("client").
// Where("status = ?", 1).And("country = ?", "CL")
//
// Also can be used in join and having clauses
func (st *SelectStm) And(expr string, p ...any) *SelectStm {
st.clause("AND", expr, p...)
return st
}
// AndIf adds a condition to the query connecting with an AND operator only when cond parameter is true
//
// # Example
//
// filterByCountry = true
// s := Select().Col("*").From("client").
// Where("status = ?", 1).AndIf("country = ?", "CL")
//
// Also can be used in join and having clauses
func (st *SelectStm) AndIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.clause("AND", expr, p...)
}
return st
}
// Y adds an AND conector to the stament where is called. Its helpful when used with In()
//
// # Example
//
// Select().
// Col("*").
// From("client").
// Where("country = ?", "CL").
// Y().
// In("status", "", 1, 2, 3, 4)
//
// Produces: SELECT * FROM client WHERE country = ? AND status IN (?, ?, ?, ?)
func (up *SelectStm) Y() *SelectStm {
up.clause("AND", "")
return up
}
func (st *SelectStm) Or(expr string, p ...any) *SelectStm {
st.clause("OR", expr, p...)
return st
}
func (st *SelectStm) OrIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.clause("OR", expr, p...)
}
return st
}
// Like adds a LIKE clause to the query after the las clause added
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").And("city").Like("'%ago%'")
//
// Observe that if you use it like Select().Like(..., will produce "SELECT LIKE"
func (st *SelectStm) Like(expr string, p ...any) *SelectStm {
st.clause("LIKE", expr, p...)
return st
}
// LikeIf adds a LIKE clause to the query after the las clause added, when cond is true
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").And("city").LikeIf(true, "'%ago%'")
func (st *SelectStm) LikeIf(cond bool, expr string, p ...any) *SelectStm {
if cond {
st.clause("LIKE", expr, p...)
}
return st
}
// In adds a IN clause to the query after the las clause added
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").And("city").In("'Nagoya'", "'Tokio", "'Parral'")
func (st *SelectStm) In(expr string, p ...any) *SelectStm {
st.clause("IN (", expr+")", p...)
return st
}
// InArgs adds an In clause to the stament automatically setting the positional parameters of the query based on the
// passed parameters
func (up *SelectStm) InArgs(value string, p ...any) *SelectStm {
up.stament.inArgs(value, p...)
return up
}
// GroupBy adds a GROUP BY clause to the query
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").GroupBy("a1")
func (st *SelectStm) GroupBy(grp string, p ...any) *SelectStm {
if !st.grouped {
st.add(groupS, "GROUP BY", grp, p...)
st.grouped = true
} else {
st.add(groupS, ",", grp, p...)
}
return st
}
// Having adds a HAVING clause to the query
//
// # Example
//
// Select().Col("a1, a2, a3, COUNT(1) AS how_many").From("client").Where("1 = 1").GroupBy("a1").Having(how_many > 100)
func (st *SelectStm) Having(hav string, p ...any) *SelectStm {
st.add(havingS, "HAVING", hav, p...)
return st
}
// OrderBy adds an ORDER BY clause to the query
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").OrderBy("a1 ASC")
func (st *SelectStm) OrderBy(expr string, p ...any) *SelectStm {
st.add(orderS, "ORDER BY", expr, p...)
return st
}
// Limit adds a LIMIT clause to the query
//
// # Example
//
// Select().Col("a1, a2, a3").From("client").Where("1 = 1").Limit(100)
func (st *SelectStm) Limit(limit int) *SelectStm {
st.add(limitS, "LIMIT", "?", limit)
return st
}
func (st *SelectStm) Offset(off int) *SelectStm {
st.add(offsetS, "OFFSET", "?", off)
return st
}
// Clause adds a custom clause to the query in the position were is invoked
//
// # Example
//
// Select().Clause("SQL NO CACHE").Col("a1, a2, a3").From("client").Where("1 = 1")
func (st *SelectStm) Clause(clause, expr string, p ...any) *SelectStm {
st.add(st.lastPos, clause, expr, p...)
return st
}
// ClauseIf adds a custom clause to the query in the position were is invoked, whencond is true
//
// # Example
//
// Select().ClauseIf(true, "SQL NO CACHE").Col("a1, a2, a3").From("client").Where("1 = 1")
func (st *SelectStm) ClauseIf(cond bool, clause, expr string, p ...any) *SelectStm {
if cond {
st.add(st.lastPos, clause, expr, p...)
}
return st
}
package obreron
// UpdateStm represents an update stament
type UpdateStm struct {
*stament
}
// Update returns an update stament
//
// # Example
//
// upd := Update("client").Set("status = 0").Where("status = ?", 1)
//
// query, p := upd.Build() // builds UPDATE client SET status = 0 WHERE status = ? and stores in p []any{1}
//
// r, err := db.Exec(query, p...)
func Update(table string) *UpdateStm {
d := &UpdateStm{
stament: pool.Get().(*stament),
}
d.firstCol = true
d.add(updateS, "UPDATE", table)
return d
}
// ColSelect is a helper method which provides a way to build an update (select ...) stament
//
// # Example
//
// upd := Update("items").
// ColSelectIf(
// true,
// Select().
// Col("id, retail / wholesale AS markup, quantity").
// From("items"), "discounted"
// ).Set("items.retail = items.retail * 0.9").
// Set("a = 2").
// SetIf(true, "c = 3").
// Where("discounted.markup >= 1.3").
// And("discounted.quantity < 100").
// And("items.id = discounted.id").
//
// query, p := upd.Build() // builds UPDATE items, ( SELECT id, retail / wholesale AS markup, quantity FROM items) discounted SET a = 2, c = 3 WHERE 1 = 1 AND discounted.markup >= 1.3 AND discounted.quantity < 100 AND items.id = discounted.id
func (up *UpdateStm) ColSelect(col *SelectStm, alias string) *UpdateStm {
up.Clause(",(", "")
q, p := col.Build()
up.Clause(q, "", p...)
up.Clause(")", "")
up.Clause(alias, "")
return up
}
// ColSelectIf does the same work as [ColSelect] only when the cond parameter is true
func (up *UpdateStm) ColSelectIf(cond bool, col *SelectStm, alias string) *UpdateStm {
if cond {
up.ColSelect(col, alias)
}
return up
}
// Set adds set clause to the update stament
//
// # Examples
//
// upd := Update("client").Set("status = 0").Where("status = ?", 1)
// up2 := Update("client").Set("status = ?", 0).Where("status = ?", 1)
// up3 := Update("client").Set("status = ?", 0).Set("name = ?", "stitch").Where("status = ?", 1)
func (up *UpdateStm) Set(expr string, p ...any) *UpdateStm {
if !up.firstCol {
up.Clause(", ", "")
up.add(setS, "", expr, p...)
} else {
up.firstCol = false
up.add(setS, "SET", expr, p...)
}
return up
}
// Set adds set clause to the update stament when the cond param is true
func (up *UpdateStm) SetIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.Set(expr, p...)
}
return up
}
// Where adds a where clause to the update stament
func (up *UpdateStm) Where(cond string, p ...any) *UpdateStm {
up.where(cond, p...)
return up
}
// Y adds an AND conector to the stament where is called. Its helpful when used with In()
//
// # Example
//
// Update("client").Set("status = 0").Where("country = ?", "CL").Y().In("status", "", 1, 2, 3, 4)
//
// Produces: UPDATE client SET status = 0 WHERE country = ? AND status IN (?, ?, ?, ?)
func (up *UpdateStm) Y() *UpdateStm {
up.clause("AND", "")
return up
}
// And adds an AND conector with eventual parameters to the stament where is called
func (up *UpdateStm) And(expr string, p ...any) *UpdateStm {
up.clause("AND", expr, p...)
return up
}
// And adds an AND conector with eventual parameters to the stament where is called, only when
// cond parameter is true
func (up *UpdateStm) AndIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.clause("AND", expr, p...)
}
return up
}
// Or adds an Or connector with eventual parameters to the stament where is called
func (up *UpdateStm) Or(expr string, p ...any) *UpdateStm {
up.clause("OR", expr, p...)
return up
}
// OrIf adds an Or connector with eventual parameters to the stament where is called only when cond parameter value is true
func (up *UpdateStm) OrIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.clause("OR", expr, p...)
}
return up
}
// Like adds a LIKE clause to the query after the last added clause
//
// # Example
//
// Update("items").
// Set("items.retail = items.retail * 0.9").
// Set("a = 2").
// Where("discounted.markup >= 1.3").
// And("colX").
// Like("'%ago%'")
func (up *UpdateStm) Like(expr string, p ...any) *UpdateStm {
up.clause("LIKE", expr, p...)
return up
}
// LikeIf adds a LIKE clause to the query after the last added clause only when cond parameter value is true
//
// # Example
//
// Update("items").
// Set("items.retail = items.retail * 0.9").
// Set("a = 2").
// Where("discounted.markup >= 1.3").
// And("colX").
// Like("'%ago%'")
func (up *UpdateStm) LikeIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.clause("LIKE", expr, p...)
}
return up
}
// In adds a IN clause to the query after the las clause added
//
// # Example
//
// Update("client").
// Set("status = 0").
// Where("country = ?", "CL").
// Y().In("status", "?, ?, ?, ?", 1, 2, 3, 4)
func (up *UpdateStm) In(value, expr string, p ...any) *UpdateStm {
up.clause(value+" IN ("+expr+")", "", p...)
return up
}
// InArgs adds an In clause to the stament automatically setting the positional parameters of the query based on the
// passed parameters
//
// # Example
//
// Update("client").Set("status = 0").Where("country = ?", "CL").Y().InArgs("status", 1, 2, 3, 4)
//
// Produces: UPDATE client SET status = 0 WHERE country = ? AND status IN (?, ?, ?, ?)"
func (up *UpdateStm) InArgs(value string, p ...any) *UpdateStm {
up.stament.inArgs(value, p...)
return up
}
// Close frees up the resources used in the stament
func (up *UpdateStm) Close() {
CloseStament(up.stament)
}
func (up *UpdateStm) OrderBy(expr string, p ...any) *UpdateStm {
up.add(limitS, "ORDER BY", expr, p...)
return up
}
func (up *UpdateStm) Limit(limit int) *UpdateStm {
up.add(limitS, "LIMIT", "?", limit)
return up
}
func (up *UpdateStm) Clause(clause, expr string, p ...any) *UpdateStm {
up.add(up.lastPos, clause, expr, p...)
return up
}
func (up *UpdateStm) ClauseIf(cond bool, clause, expr string, p ...any) *UpdateStm {
if cond {
up.Clause(clause, expr, p...)
}
return up
}
// Join adds a relation to the query in the form of an inner join
//
// # Example
//
// Update("business AS b").
// Join("business_geocode AS g").On("b.business_id = g.business_id").
// Set("b.mapx = g.latitude, b.mapy = g.longitude").
// Where("(b.mapx = '' or b.mapx = 0)").And("g.latitude > 0")
//
// OUTPUT:
// UPDATE business AS b JOIN business_geocode AS g ON b.business_id = g.business_id SET b.mapx = g.latitude, b.mapy = g.longitude WHERE (b.mapx = '' or b.mapx = 0) AND g.latitude > 0 AND 3 = 3
func (up *UpdateStm) Join(expr string, p ...any) *UpdateStm {
up.add(updateS, "JOIN", expr, p...)
return up
}
func (up *UpdateStm) JoinIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.Join(expr, p...)
}
return up
}
func (up *UpdateStm) On(on string, p ...any) *UpdateStm {
up.clause("ON", on, p...)
return up
}
func (up *UpdateStm) OnIf(cond bool, expr string, p ...any) *UpdateStm {
if cond {
up.On(expr, p...)
}
return up
}