Files
pgm/qry.go

245 lines
4.2 KiB
Go

// Patial Tech.
// Author, Ankit Patial
package pgm
import (
"context"
"strconv"
"strings"
"github.com/jackc/pgx/v5"
)
type (
Clause interface {
Select(fields ...Field) SelectClause
// Insert() InsertSet
// Update() UpdateSet
// Delete() WhereOrExec
}
SelectClause interface {
// Join and Inner Join are same
Join(m Table, t1Field, t2Field Field) SelectClause
LeftJoin(m Table, t1Field, t2Field Field) SelectClause
RightJoin(m Table, t1Field, t2Field Field) SelectClause
FullJoin(m Table, t1Field, t2Field Field) SelectClause
CrossJoin(m Table) SelectClause
WhereClause
OrderByClause
GroupByClause
LimitClause
OffsetClause
Query
raw(prefixArgs []any) (string, []any)
}
WhereClause interface {
Where(cond ...Conditioner) AfterWhere
}
AfterWhere interface {
WhereClause
GroupByClause
OrderByClause
LimitClause
OffsetClause
Query
}
GroupByClause interface {
GroupBy(fields ...Field) AfterGroupBy
}
AfterGroupBy interface {
HavinClause
OrderByClause
LimitClause
OffsetClause
Query
}
HavinClause interface {
Having(cond ...Conditioner) AfterHaving
}
AfterHaving interface {
OrderByClause
LimitClause
OffsetClause
Query
}
OrderByClause interface {
OrderBy(fields ...Field) AfterOrderBy
}
AfterOrderBy interface {
LimitClause
OffsetClause
Query
}
LimitClause interface {
Limit(v int) AfterLimit
}
AfterLimit interface {
OffsetClause
Query
}
OffsetClause interface {
Offset(v int) AfterOffset
}
AfterOffset interface {
LimitClause
Query
}
Conditioner interface {
Condition(args *[]any, idx int) string
}
Insert interface {
Set(field Field, val any) InsertClause
SetMap(fields map[Field]any) InsertClause
}
InsertClause interface {
Insert
Returning(field Field) First
OnConflict(fields ...Field) Do
Execute
Stringer
}
Do interface {
DoNothing() Execute
DoUpdate(fields ...Field) Execute
}
Update interface {
Set(field Field, val any) UpdateClause
SetMap(fields map[Field]any) UpdateClause
}
UpdateClause interface {
Update
Where(cond ...Conditioner) WhereOrExec
}
WhereOrExec interface {
Where(cond ...Conditioner) WhereOrExec
Execute
}
Query interface {
First
All
Stringer
}
First interface {
First(ctx context.Context, dest ...any) error
FirstTx(ctx context.Context, tx pgx.Tx, dest ...any) error
Stringer
}
All interface {
// Query rows
//
// don't forget to close() rows
All(ctx context.Context, rows RowsCb) error
// Query rows
//
// don't forget to close() rows
AllTx(ctx context.Context, tx pgx.Tx, rows RowsCb) error
}
Execute interface {
Exec(ctx context.Context) error
ExecTx(ctx context.Context, tx pgx.Tx) error
Stringer
}
Stringer interface {
String() string
}
RowScanner interface {
Scan(dest ...any) error
}
RowsCb func(row RowScanner) error
)
func joinFileds(fields []Field) string {
sb := getSB()
defer putSB(sb)
for i, f := range fields {
if i == 0 {
sb.WriteString(f.String())
} else {
sb.WriteString(", ")
sb.WriteString(f.String())
}
}
return sb.String()
}
func And(cond ...Conditioner) Conditioner {
return &CondGroup{op: " AND ", cond: cond}
}
func Or(cond ...Conditioner) Conditioner {
return &CondGroup{op: " OR ", cond: cond}
}
func (cv *Cond) Condition(args *[]any, argIdx int) string {
// 1. condition with subquery
if cv.action == CondActionSubQuery {
qStr, newArgs := cv.Val.(SelectClause).raw(*args)
*args = newArgs
return cv.Field + strings.Replace(cv.op, "$", qStr, 1)
}
// 2. normal condition
var op string
if cv.Val != nil {
*args = append(*args, cv.Val)
if strings.HasSuffix(cv.op, "$") {
op = cv.op + strconv.Itoa(argIdx+1)
} else {
op = strings.Replace(cv.op, "$", "$"+strconv.Itoa(argIdx+1), 1)
}
} else {
op = cv.op
}
if cv.action == CondActionNeedToClose {
return cv.Field + op + ")"
}
return cv.Field + op
}
func (c *CondGroup) Condition(args *[]any, argIdx int) string {
sb := getSB()
defer putSB(sb)
sb.WriteString("(")
for i, cond := range c.cond {
if i == 0 {
sb.WriteString(cond.Condition(args, argIdx+i))
} else {
sb.WriteString(c.op)
sb.WriteString(cond.Condition(args, argIdx+i))
}
}
sb.WriteString(")")
return sb.String()
}