2024-08-09 15:00:52 +00:00
|
|
|
package builder
|
2024-08-07 19:16:40 +00:00
|
|
|
|
2024-08-09 22:33:10 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
2024-08-09 19:14:28 +00:00
|
|
|
|
2024-08-13 12:13:15 +00:00
|
|
|
const (
|
|
|
|
BUILDER_VERSION = "0.0.1"
|
2024-08-16 18:10:34 +00:00
|
|
|
BUILDER_CLIENT_METHODS = "Raw|In|Find|Select|Fields|Join|Group|Sort|Limit|Offset|Delete|Insert|Set|Update|OnConflict|DoUpdate|DoNothing"
|
2024-08-13 12:13:15 +00:00
|
|
|
BUILDER_SERVER_METHODS = "Sql"
|
|
|
|
)
|
|
|
|
|
2024-08-11 14:29:42 +00:00
|
|
|
type Builder struct {
|
2024-08-15 15:52:21 +00:00
|
|
|
TableName string
|
|
|
|
TableAlias string
|
|
|
|
Parts SQLParts
|
|
|
|
Dialect Dialect
|
|
|
|
LastQuery Find
|
|
|
|
Transaction bool
|
2024-08-16 18:10:34 +00:00
|
|
|
RawSql RawSql
|
2024-08-11 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 19:16:40 +00:00
|
|
|
type SQLParts struct {
|
2024-08-09 19:14:28 +00:00
|
|
|
Operation string
|
|
|
|
From string
|
|
|
|
FieldsExp string
|
|
|
|
FromExp string
|
|
|
|
HavingExp string
|
|
|
|
FiterExp string
|
|
|
|
JoinExps []string
|
|
|
|
GroupExp string
|
|
|
|
OrderExp string
|
|
|
|
LimitExp string
|
2024-08-09 22:33:10 +00:00
|
|
|
OffsetExp string
|
2024-08-12 18:21:34 +00:00
|
|
|
Values []interface{}
|
2024-08-09 22:33:10 +00:00
|
|
|
Insert InsertData
|
|
|
|
Update UpdateData
|
2024-08-07 19:16:40 +00:00
|
|
|
}
|
|
|
|
|
2024-08-11 19:49:19 +00:00
|
|
|
func New(dialect Dialect) *Builder {
|
2024-08-09 19:14:28 +00:00
|
|
|
return &Builder{
|
|
|
|
Parts: SQLParts{
|
|
|
|
Operation: "SELECT",
|
|
|
|
From: "FROM",
|
|
|
|
},
|
2024-08-11 19:49:19 +00:00
|
|
|
Dialect: dialect,
|
2024-08-09 19:14:28 +00:00
|
|
|
}
|
2024-08-07 19:16:40 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 18:10:34 +00:00
|
|
|
func (b *Builder) Raw(sql map[string]interface{}) *Builder {
|
|
|
|
b.Parts.Operation = "RAW"
|
|
|
|
b.RawSql = sql
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-09 19:14:28 +00:00
|
|
|
func (b *Builder) In(table string) *Builder {
|
|
|
|
b.TableName, b.TableAlias = getTableAlias(table)
|
|
|
|
b.Parts.FromExp = table
|
2024-08-11 19:49:19 +00:00
|
|
|
b.Dialect = b.Dialect.New(DialectOpts{
|
2024-08-09 19:14:28 +00:00
|
|
|
"TableName": b.TableName,
|
|
|
|
"TableAlias": b.TableAlias,
|
|
|
|
})
|
2024-08-07 19:16:40 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-09 19:14:28 +00:00
|
|
|
func (b *Builder) Find(query Find) *Builder {
|
2024-08-15 15:52:21 +00:00
|
|
|
b.LastQuery = query
|
2024-08-12 18:21:34 +00:00
|
|
|
b.Parts.FiterExp, b.Parts.Values = covertFind(
|
2024-08-11 19:49:19 +00:00
|
|
|
b.Dialect,
|
2024-08-09 19:14:28 +00:00
|
|
|
query,
|
|
|
|
)
|
2024-08-15 15:52:21 +00:00
|
|
|
if len(b.Parts.Operation) == 0 {
|
2024-08-09 19:14:28 +00:00
|
|
|
b.Parts.Operation = "SELECT"
|
|
|
|
}
|
2024-08-15 15:52:21 +00:00
|
|
|
if len(b.Parts.HavingExp) == 0 {
|
2024-08-09 19:14:28 +00:00
|
|
|
b.Parts.HavingExp = "WHERE"
|
|
|
|
}
|
2024-08-15 15:52:21 +00:00
|
|
|
if len(b.Parts.FieldsExp) == 0 {
|
2024-08-09 19:14:28 +00:00
|
|
|
b.Parts.FieldsExp = "*"
|
|
|
|
}
|
2024-08-15 15:52:21 +00:00
|
|
|
if len(b.Parts.FiterExp) == 0 {
|
|
|
|
b.Parts.HavingExp = ""
|
|
|
|
}
|
2024-08-07 19:16:40 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:33:10 +00:00
|
|
|
func (b *Builder) Select(fields ...Map) *Builder {
|
|
|
|
fieldsExp, err := convertFields(fields)
|
|
|
|
if err != nil {
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
b.Parts.FieldsExp = fieldsExp
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) Fields(fields ...Map) *Builder {
|
|
|
|
return b.Select(fields...)
|
|
|
|
}
|
|
|
|
|
2024-08-09 19:14:28 +00:00
|
|
|
func (b *Builder) Join(joins ...interface{}) *Builder {
|
2024-08-12 18:21:34 +00:00
|
|
|
exps, vals := convertJoin(b.Dialect, joins...)
|
|
|
|
b.Parts.JoinExps = append(b.Parts.JoinExps, exps...)
|
|
|
|
b.Parts.Values = append(b.Parts.Values, vals...)
|
2024-08-07 19:16:40 +00:00
|
|
|
return b
|
|
|
|
}
|
2024-08-09 19:14:28 +00:00
|
|
|
|
2024-08-09 22:33:10 +00:00
|
|
|
func (b *Builder) Group(keys ...string) *Builder {
|
|
|
|
b.Parts.HavingExp = "HAVING"
|
2024-08-11 19:49:19 +00:00
|
|
|
b.Parts.GroupExp = convertGroup(b.Dialect, keys)
|
2024-08-09 22:33:10 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) Sort(sort Map) *Builder {
|
2024-08-11 19:49:19 +00:00
|
|
|
b.Parts.OrderExp, _ = convertSort(b.Dialect, sort)
|
2024-08-09 22:33:10 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-09-02 10:37:34 +00:00
|
|
|
func (b *Builder) Limit(limit int64) *Builder {
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts.LimitExp = fmt.Sprintf("LIMIT %d", limit)
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-09-02 10:37:34 +00:00
|
|
|
func (b *Builder) Offset(offset int64) *Builder {
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts.OffsetExp = fmt.Sprintf("OFFSET %d", offset)
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) Delete() *Builder {
|
|
|
|
b.Parts.Operation = "DELETE"
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-15 15:52:21 +00:00
|
|
|
func (b *Builder) Insert(inserts ...Map) *Builder {
|
2024-08-11 19:49:19 +00:00
|
|
|
insertData, _ := convertInsert(b.Dialect, inserts)
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts = SQLParts{
|
|
|
|
Operation: "INSERT INTO",
|
|
|
|
Insert: insertData,
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) Set(updates Map) *Builder {
|
2024-08-15 15:52:21 +00:00
|
|
|
b.Dialect = b.Dialect.New(DialectOpts{
|
|
|
|
"TableAlias": "",
|
|
|
|
})
|
2024-08-11 19:49:19 +00:00
|
|
|
updateData := convertUpdate(b.Dialect, updates)
|
2024-08-15 15:52:21 +00:00
|
|
|
b.Find(b.LastQuery)
|
|
|
|
b.Parts.Operation = "UPDATE"
|
|
|
|
b.Parts.Update = updateData
|
2024-08-09 22:33:10 +00:00
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) Update(updates Map) *Builder {
|
|
|
|
return b.Set(updates)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) OnConflict(fields ...string) *Builder {
|
|
|
|
if b.Parts.Operation == "UPDATE" {
|
2024-08-11 19:49:19 +00:00
|
|
|
b.Parts.Update.Upsert = convertConflict(b.Dialect, fields...)
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts.Update.UpsertExp = "DO NOTHING"
|
2024-08-11 14:29:42 +00:00
|
|
|
} else {
|
|
|
|
panic("OnConflict is only available for UPDATE operation")
|
2024-08-09 22:33:10 +00:00
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) DoUpdate(fields ...string) *Builder {
|
|
|
|
if b.Parts.Operation == "UPDATE" {
|
|
|
|
b.Parts.Update.UpsertExp = convertUpsert(fields)
|
2024-08-11 14:29:42 +00:00
|
|
|
} else {
|
|
|
|
panic("DoUpdate is only available for UPDATE operation")
|
2024-08-09 22:33:10 +00:00
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Builder) DoNothing() *Builder {
|
|
|
|
if b.Parts.Operation == "UPDATE" {
|
|
|
|
b.Parts.Update.UpsertExp = "DO NOTHING"
|
2024-08-11 14:29:42 +00:00
|
|
|
} else {
|
|
|
|
panic("DoNothing is only available for UPDATE operation")
|
2024-08-09 22:33:10 +00:00
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-15 15:52:21 +00:00
|
|
|
func (b *Builder) Tx() *Builder {
|
|
|
|
b.Transaction = true
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:33:10 +00:00
|
|
|
func (b *Builder) Sql() (string, []interface{}) {
|
2024-08-09 19:14:28 +00:00
|
|
|
operation := b.Parts.Operation
|
|
|
|
switch {
|
2024-08-16 18:10:34 +00:00
|
|
|
case operation == "RAW":
|
|
|
|
return b.RawSql["s"].(string), b.RawSql["v"].([]interface{})
|
2024-08-09 19:14:28 +00:00
|
|
|
case operation == "SELECT" || operation == "SELECT DISTINCT":
|
|
|
|
return unspace(strings.Join([]string{
|
|
|
|
b.Parts.Operation,
|
|
|
|
b.Parts.FieldsExp,
|
|
|
|
b.Parts.From,
|
|
|
|
b.Parts.FromExp,
|
|
|
|
strings.Join(
|
|
|
|
b.Parts.JoinExps,
|
|
|
|
" ",
|
|
|
|
),
|
|
|
|
b.Parts.GroupExp,
|
|
|
|
b.Parts.HavingExp,
|
|
|
|
b.Parts.FiterExp,
|
|
|
|
b.Parts.OrderExp,
|
|
|
|
b.Parts.LimitExp,
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts.OffsetExp,
|
2024-08-12 18:21:34 +00:00
|
|
|
}, " ")), b.Parts.Values
|
2024-08-09 22:33:10 +00:00
|
|
|
case operation == "DELETE":
|
|
|
|
return unspace(strings.Join([]string{
|
|
|
|
b.Parts.Operation,
|
|
|
|
b.Parts.From,
|
|
|
|
b.Parts.FromExp,
|
|
|
|
b.Parts.HavingExp,
|
|
|
|
b.Parts.FiterExp,
|
|
|
|
b.Parts.OrderExp,
|
|
|
|
b.Parts.LimitExp,
|
|
|
|
b.Parts.OffsetExp,
|
2024-08-12 18:21:34 +00:00
|
|
|
}, " ")), b.Parts.Values
|
2024-08-09 22:33:10 +00:00
|
|
|
case operation == "INSERT INTO":
|
|
|
|
return b.Parts.Insert.Statement, b.Parts.Insert.Values
|
|
|
|
case operation == "UPDATE":
|
2024-08-15 15:52:21 +00:00
|
|
|
values := append(b.Parts.Update.Values, b.Parts.Values...)
|
2024-08-09 22:33:10 +00:00
|
|
|
return unspace(strings.Join([]string{
|
|
|
|
b.Parts.Update.Statement,
|
2024-08-15 15:52:21 +00:00
|
|
|
b.Parts.HavingExp,
|
|
|
|
b.Parts.FiterExp,
|
|
|
|
b.Parts.OrderExp,
|
|
|
|
b.Parts.LimitExp,
|
|
|
|
b.Parts.OffsetExp,
|
2024-08-09 22:33:10 +00:00
|
|
|
b.Parts.Update.Upsert,
|
|
|
|
b.Parts.Update.UpsertExp,
|
2024-08-15 15:52:21 +00:00
|
|
|
}, " ")), values
|
2024-08-09 19:14:28 +00:00
|
|
|
default:
|
2024-08-09 22:33:10 +00:00
|
|
|
return "", nil
|
2024-08-09 19:14:28 +00:00
|
|
|
}
|
|
|
|
}
|