Global AND and OR functions for better indentation of a complex condition in the Go code and in the generated SQL.

This commit is contained in:
go-jet 2022-02-11 13:09:49 +01:00
parent 8ffbe38993
commit 9f91fd705a
17 changed files with 338 additions and 44 deletions

View file

@ -98,9 +98,9 @@ func (c *ClauseWhere) Serialize(statementType StatementType, out *SQLBuilder, op
}
out.WriteString("WHERE")
out.IncreaseIdent()
out.IncreaseIdent(6)
c.Condition.serialize(statementType, out, NoWrap.WithFallTrough(options)...)
out.DecreaseIdent()
out.DecreaseIdent(6)
}
// ClauseGroupBy struct

View file

@ -123,6 +123,65 @@ func (c *binaryOperatorExpression) serialize(statement StatementType, out *SQLBu
}
}
type expressionListOperator struct {
ExpressionInterfaceImpl
operator string
expressions []Expression
}
func newExpressionListOperator(operator string, expressions ...Expression) *expressionListOperator {
ret := &expressionListOperator{
operator: operator,
expressions: expressions,
}
ret.ExpressionInterfaceImpl.Parent = ret
return ret
}
func newBoolExpressionListOperator(operator string, expressions ...BoolExpression) BoolExpression {
return BoolExp(newExpressionListOperator(operator, BoolExpressionListToExpressionList(expressions)...))
}
func (elo *expressionListOperator) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if len(elo.expressions) == 0 {
panic("jet: syntax error, expression list empty")
}
shouldWrap := len(elo.expressions) > 1
if shouldWrap {
out.WriteByte('(')
out.IncreaseIdent(tabSize)
out.NewLine()
}
for i, expression := range elo.expressions {
if i == 1 {
out.IncreaseIdent(tabSize)
}
if i > 0 {
out.NewLine()
out.WriteString(elo.operator)
}
out.IncreaseIdent(len(elo.operator) + 1)
expression.serialize(statement, out, FallTrough(options)...)
out.DecreaseIdent(len(elo.operator) + 1)
}
if len(elo.expressions) > 1 {
out.DecreaseIdent(tabSize)
}
if shouldWrap {
out.DecreaseIdent(tabSize)
out.NewLine()
out.WriteByte(')')
}
}
// A prefix operator Expression
type prefixExpression struct {
ExpressionInterfaceImpl
@ -209,8 +268,8 @@ type complexExpression struct {
expressions Expression
}
func complexExpr(expressions Expression) Expression {
complexExpression := &complexExpression{expressions: expressions}
func complexExpr(expression Expression) Expression {
complexExpression := &complexExpression{expressions: expression}
complexExpression.ExpressionInterfaceImpl.Parent = complexExpression
return complexExpression

View file

@ -1,5 +1,17 @@
package jet
// AND function adds AND operator between expressions. This function can be used, instead of method AND,
// to have a better inlining of a complex condition in the Go code and in the generated SQL.
func AND(expressions ...BoolExpression) BoolExpression {
return newBoolExpressionListOperator("AND", expressions...)
}
// OR function adds OR operator between expressions. This function can be used, instead of method OR,
// to have a better inlining of a complex condition in the Go code and in the generated SQL.
func OR(expressions ...BoolExpression) BoolExpression {
return newBoolExpressionListOperator("OR", expressions...)
}
// ROW is construct one table row from list of expressions.
func ROW(expressions ...Expression) Expression {
return NewFunc("ROW", expressions, nil)

View file

@ -4,6 +4,28 @@ import (
"testing"
)
func TestAND(t *testing.T) {
assertClauseSerializeErr(t, AND(), "jet: syntax error, expression list empty")
assertClauseSerialize(t, AND(table1ColInt.IS_NULL()), `table1.col_int IS NULL`) // IS NULL doesn't add parenthesis
assertClauseSerialize(t, AND(table1ColInt.LT(Int(11))), `(table1.col_int < $1)`, int64(11))
assertClauseSerialize(t, AND(table1ColInt.GT(Int(11)), table1ColFloat.EQ(Float(0))),
`(
(table1.col_int > $1)
AND (table1.col_float = $2)
)`, int64(11), 0.0)
}
func TestOR(t *testing.T) {
assertClauseSerializeErr(t, OR(), "jet: syntax error, expression list empty")
assertClauseSerialize(t, OR(table1ColInt.IS_NULL()), `table1.col_int IS NULL`) // IS NULL doesn't add parenthesis
assertClauseSerialize(t, OR(table1ColInt.LT(Int(11))), `(table1.col_int < $1)`, int64(11))
assertClauseSerialize(t, OR(table1ColInt.GT(Int(11)), table1ColFloat.EQ(Float(0))),
`(
(table1.col_int > $1)
OR (table1.col_float = $2)
)`, int64(11), 0.0)
}
func TestFuncAVG(t *testing.T) {
assertClauseSerialize(t, AVG(table1ColFloat), "AVG(table1.col_float)")
assertClauseSerialize(t, AVG(table1ColInt), "AVG(table1.col_int)")

View file

@ -26,6 +26,7 @@ type SQLBuilder struct {
Debug bool
}
const tabSize = 4
const defaultIdent = 5
// IncreaseIdent adds ident or defaultIdent number of spaces to each new line

View file

@ -113,6 +113,17 @@ func ExpressionListToSerializerList(expressions []Expression) []Serializer {
return ret
}
// BoolExpressionListToExpressionList converts list of bool expressions to list of expressions
func BoolExpressionListToExpressionList(expressions []BoolExpression) []Expression {
var ret []Expression
for _, expression := range expressions {
ret = append(ret, expression)
}
return ret
}
// ColumnListToProjectionList func
func ColumnListToProjectionList(columns []ColumnExpression) []Projection {
var ret []Projection