uni/WEB43-diary/internal/database/whereBuilder.go

117 lines
2.8 KiB
Go

package database
import (
"fmt"
"strings"
)
type SQLOperator string
type LogicalOperator string
func GetLogicFromString(operator string) LogicalOperator {
switch strings.ToUpper(operator) {
case "OR":
return OR
default:
return AND
}
}
const (
Equal SQLOperator = "="
GreaterThan SQLOperator = ">"
LessThan SQLOperator = "<"
GreaterOrEqual SQLOperator = ">="
LessOrEqual SQLOperator = "<="
NotEqual SQLOperator = "<>"
Like SQLOperator = "LIKE"
In SQLOperator = "IN"
AND LogicalOperator = "AND"
OR LogicalOperator = "OR"
)
type QueryCondition struct {
Row string
Operator SQLOperator
Value any
}
type WhereGroup struct {
Conditions []*QueryCondition
Logic LogicalOperator
SubGroups WhereGroups
}
type WhereGroups []*WhereGroup
func (group *WhereGroup) AddCondition(condition *QueryCondition) {
group.Conditions = append(group.Conditions, condition)
}
func (group *WhereGroup) AddSubGroup(subGroup *WhereGroup) {
group.SubGroups = append(group.SubGroups, subGroup)
}
func (groups WhereGroups) Build(prependWhere bool) (string, []any) {
var whereStatement string
var queryValues []any
groupsLen := len(groups)
if prependWhere && groupsLen > 0 {
whereStatement = " WHERE "
}
groupStrings := []string{}
for _, group := range groups {
conditionsLen := len(group.Conditions)
subsLen := len(group.SubGroups)
if conditionsLen == 0 && subsLen == 0 {
continue
}
subQuery := strings.Builder{}
subQuery.WriteString("(")
if conditionsLen > 0 {
groupConditions := make([]string, conditionsLen)
for i, condition := range group.Conditions {
switch condition.Operator {
case In:
values, ok := condition.Value.([]string)
if ok {
placeholders := strings.Repeat("?,", len(values))
placeholders = placeholders[:len(placeholders)-1] // Remove trailing comma
groupConditions[i] = fmt.Sprintf("%s %s (%s)", condition.Row, condition.Operator, placeholders)
for _, v := range values {
queryValues = append(queryValues, v)
}
continue
}
fallthrough
default:
groupConditions[i] = fmt.Sprintf("%s %s ?", condition.Row, condition.Operator)
queryValues = append(queryValues, condition.Value)
}
}
subQuery.WriteString(strings.Join(groupConditions, fmt.Sprintf(" %s ", group.Logic)))
}
if subsLen > 0 {
if conditionsLen > 0 {
subQuery.WriteString(fmt.Sprintf(" %s ", group.Logic))
}
subGroupStatement, values := group.SubGroups.Build(false)
subQuery.WriteString(subGroupStatement)
queryValues = append(queryValues, values...)
}
subQuery.WriteString(")")
groupStrings = append(groupStrings, subQuery.String())
}
whereStatement += strings.Join(groupStrings, fmt.Sprintf(" %s ", AND))
return whereStatement, queryValues
}