Simplify construction of new expressions.
Fixes: IS_NOT_NULL() does not always add enough parentheses to the compiled SQL #500
This commit is contained in:
parent
95224a793f
commit
4995a90483
26 changed files with 466 additions and 543 deletions
|
|
@ -71,7 +71,7 @@ func (a arrayInterfaceImpl[E]) CONCAT_ELEMENT(rhs E) Array[E] {
|
|||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) AT(at IntegerExpression) E {
|
||||
return CastToArrayElemType[E](a.parent, CustomExpression(a.parent, Token("["), at, Token("]")))
|
||||
return CastToArrayElemType[E](a.parent, AtomicCustomExpression(a.parent, Token("["), at, Token("]")))
|
||||
}
|
||||
|
||||
type arrayExpressionWrapper[E Expression] struct {
|
||||
|
|
@ -126,12 +126,8 @@ func CastToArrayElemType[E Expression](array Array[E], exp Expression) E {
|
|||
|
||||
// ARRAY constructor builds an array value using list of expressions.
|
||||
func ARRAY[E Expression](elems ...E) Array[E] {
|
||||
var args = make([]Serializer, len(elems))
|
||||
for i, each := range elems {
|
||||
args[i] = each
|
||||
}
|
||||
return ArrayExp[E](CustomExpression(Token("ARRAY["), ListSerializer{
|
||||
Serializers: args,
|
||||
return ArrayExp[E](AtomicCustomExpression(Token("ARRAY["), ListSerializer{
|
||||
Serializers: ToSerializerList(elems),
|
||||
Separator: ",",
|
||||
}, Token("]")))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
func TestBoolExpressionEQ(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.EQ(table2ColBool), "(table1.col_bool = table2.col_bool)")
|
||||
assertClauseSerialize(t, Bool(true).EQ(String("foo").IS_NOT_NULL()), `($1 = ($2 IS NOT NULL))`, true, "foo")
|
||||
}
|
||||
|
||||
func TestBoolExpressionNOT_EQ(t *testing.T) {
|
||||
|
|
@ -24,31 +25,31 @@ func TestBoolExpressionIS_NOT_DISTINCT_FROM(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBoolExpressionIS_TRUE(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_TRUE(), "table1.col_bool IS TRUE")
|
||||
assertClauseSerialize(t, table1ColBool.IS_TRUE(), "(table1.col_bool IS TRUE)")
|
||||
assertClauseSerialize(t, (Int(2).EQ(table1ColInt)).IS_TRUE(),
|
||||
`($1 = table1.col_int) IS TRUE`, int64(2))
|
||||
`(($1 = table1.col_int) IS TRUE)`, int64(2))
|
||||
assertClauseSerialize(t, (Int(2).EQ(table1ColInt)).IS_TRUE().AND(Int(4).EQ(table2ColInt)),
|
||||
`(($1 = table1.col_int) IS TRUE AND ($2 = table2.col_int))`, int64(2), int64(4))
|
||||
`((($1 = table1.col_int) IS TRUE) AND ($2 = table2.col_int))`, int64(2), int64(4))
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_NOT_TRUE(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_TRUE(), "table1.col_bool IS NOT TRUE")
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_TRUE(), "(table1.col_bool IS NOT TRUE)")
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_FALSE(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_FALSE(), "table1.col_bool IS FALSE")
|
||||
assertClauseSerialize(t, table1ColBool.IS_FALSE(), "(table1.col_bool IS FALSE)")
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_NOT_FALSE(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_FALSE(), "table1.col_bool IS NOT FALSE")
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_FALSE(), "(table1.col_bool IS NOT FALSE)")
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_UNKNOWN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_UNKNOWN(), "table1.col_bool IS UNKNOWN")
|
||||
assertClauseSerialize(t, table1ColBool.IS_UNKNOWN(), "(table1.col_bool IS UNKNOWN)")
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_NOT_UNKNOWN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_UNKNOWN(), "table1.col_bool IS NOT UNKNOWN")
|
||||
assertClauseSerialize(t, table1ColBool.IS_NOT_UNKNOWN(), "(table1.col_bool IS NOT UNKNOWN)")
|
||||
}
|
||||
|
||||
func TestBinaryBoolExpression(t *testing.T) {
|
||||
|
|
@ -72,5 +73,5 @@ func TestBoolLiteral(t *testing.T) {
|
|||
|
||||
func TestBoolExp(t *testing.T) {
|
||||
assertClauseSerialize(t, BoolExp(String("true")), "$1", "true")
|
||||
assertClauseSerialize(t, BoolExp(String("true")).IS_TRUE(), "$1 IS TRUE", "true")
|
||||
assertClauseSerialize(t, BoolExp(String("true")).IS_TRUE(), "($1 IS TRUE)", "true")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,16 @@
|
|||
package jet
|
||||
|
||||
type enumValue struct {
|
||||
ExpressionInterfaceImpl
|
||||
stringInterfaceImpl
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
// NewEnumValue creates new named enum value
|
||||
func NewEnumValue(name string) StringExpression {
|
||||
enumValue := &enumValue{name: name}
|
||||
|
||||
enumValue.ExpressionInterfaceImpl.Root = enumValue
|
||||
enumValue.stringInterfaceImpl.root = enumValue
|
||||
|
||||
return enumValue
|
||||
return StringExp(newExpression(
|
||||
enumValueSerializer{name: name},
|
||||
))
|
||||
}
|
||||
|
||||
func (e enumValue) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
type enumValueSerializer struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e enumValueSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
out.insertConstantArgument(e.name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,33 +118,29 @@ func (e *ExpressionInterfaceImpl) serializeForOrderBy(statement StatementType, o
|
|||
e.Root.serialize(statement, out, NoWrap)
|
||||
}
|
||||
|
||||
// Representation of binary operations (e.g. comparisons, arithmetic)
|
||||
type binaryOperatorExpression struct {
|
||||
type expression struct {
|
||||
ExpressionInterfaceImpl
|
||||
Serializer
|
||||
}
|
||||
|
||||
func newExpression(serializer Serializer) Expression {
|
||||
expr := &expression{
|
||||
Serializer: serializer,
|
||||
}
|
||||
|
||||
expr.ExpressionInterfaceImpl.Root = expr
|
||||
|
||||
return expr
|
||||
}
|
||||
|
||||
// Representation of binary operations (e.g. comparisons, arithmetic)
|
||||
type binaryOperatorSerializer struct {
|
||||
lhs, rhs Serializer
|
||||
additionalParam Serializer
|
||||
operator string
|
||||
}
|
||||
|
||||
// NewBinaryOperatorExpression creates new binaryOperatorExpression
|
||||
func NewBinaryOperatorExpression(lhs, rhs Serializer, operator string, additionalParam ...Expression) Expression {
|
||||
binaryExpression := &binaryOperatorExpression{
|
||||
lhs: lhs,
|
||||
rhs: rhs,
|
||||
operator: operator,
|
||||
}
|
||||
|
||||
if len(additionalParam) > 0 {
|
||||
binaryExpression.additionalParam = additionalParam[0]
|
||||
}
|
||||
|
||||
binaryExpression.ExpressionInterfaceImpl.Root = binaryExpression
|
||||
|
||||
return complexExpr(binaryExpression)
|
||||
}
|
||||
|
||||
func (c *binaryOperatorExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
func (c *binaryOperatorSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if serializeOverride := out.Dialect.OperatorSerializeOverride(c.operator); serializeOverride != nil {
|
||||
serializeOverrideFunc := serializeOverride(c.lhs, c.rhs, c.additionalParam)
|
||||
serializeOverrideFunc(statement, out, FallTrough(options)...)
|
||||
|
|
@ -155,55 +151,48 @@ func (c *binaryOperatorExpression) serialize(statement StatementType, out *SQLBu
|
|||
}
|
||||
}
|
||||
|
||||
type expressionListOperator struct {
|
||||
ExpressionInterfaceImpl
|
||||
// NewBinaryOperatorExpression creates new binaryOperatorExpression
|
||||
func NewBinaryOperatorExpression(lhs, rhs Serializer, operator string, additionalParam ...Expression) Expression {
|
||||
return newExpression(optionalWrap(&binaryOperatorSerializer{
|
||||
lhs: lhs,
|
||||
rhs: rhs,
|
||||
additionalParam: OptionalOrDefault(additionalParam, nil),
|
||||
operator: operator,
|
||||
}))
|
||||
}
|
||||
|
||||
type serializersWithOperator struct {
|
||||
operator string
|
||||
expressions []Expression
|
||||
serializers []Serializer
|
||||
}
|
||||
|
||||
func newExpressionListOperator(operator string, expressions ...Expression) *expressionListOperator {
|
||||
ret := &expressionListOperator{
|
||||
operator: operator,
|
||||
expressions: expressions,
|
||||
}
|
||||
|
||||
ret.ExpressionInterfaceImpl.Root = ret
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func newBoolExpressionListOperator(operator string, expressions ...BoolExpression) BoolExpression {
|
||||
return BoolExp(newExpressionListOperator(operator, ToExpressionList(expressions)...))
|
||||
}
|
||||
|
||||
func (elo *expressionListOperator) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if len(elo.expressions) == 0 {
|
||||
func (s *serializersWithOperator) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if len(s.serializers) == 0 {
|
||||
panic("jet: syntax error, expression list empty")
|
||||
}
|
||||
|
||||
shouldWrap := len(elo.expressions) > 1
|
||||
shouldWrap := len(s.serializers) > 1
|
||||
if shouldWrap {
|
||||
out.WriteByte('(')
|
||||
out.IncreaseIdent(tabSize)
|
||||
out.NewLine()
|
||||
}
|
||||
|
||||
for i, expression := range elo.expressions {
|
||||
for i, expression := range s.serializers {
|
||||
if i == 1 {
|
||||
out.IncreaseIdent(tabSize)
|
||||
}
|
||||
if i > 0 {
|
||||
out.NewLine()
|
||||
out.WriteString(elo.operator)
|
||||
out.WriteString(s.operator)
|
||||
}
|
||||
|
||||
out.IncreaseIdent(len(elo.operator) + 1)
|
||||
out.IncreaseIdent(len(s.operator) + 1)
|
||||
expression.serialize(statement, out, FallTrough(options)...)
|
||||
out.DecreaseIdent(len(elo.operator) + 1)
|
||||
out.DecreaseIdent(len(s.operator) + 1)
|
||||
}
|
||||
|
||||
if len(elo.expressions) > 1 {
|
||||
if len(s.serializers) > 1 {
|
||||
out.DecreaseIdent(tabSize)
|
||||
}
|
||||
|
||||
|
|
@ -214,130 +203,47 @@ func (elo *expressionListOperator) serialize(statement StatementType, out *SQLBu
|
|||
}
|
||||
}
|
||||
|
||||
// A prefix operator Expression
|
||||
type prefixExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
|
||||
expression Expression
|
||||
operator string
|
||||
func newBoolExpressionListOperator(operator string, expressions []BoolExpression) BoolExpression {
|
||||
return BoolExp(newExpression(&serializersWithOperator{
|
||||
operator: operator,
|
||||
serializers: ToSerializerList(expressions),
|
||||
}))
|
||||
}
|
||||
|
||||
func newPrefixOperatorExpression(expression Expression, operator string) Expression {
|
||||
prefixExpression := &prefixExpression{
|
||||
expression: expression,
|
||||
operator: operator,
|
||||
}
|
||||
prefixExpression.ExpressionInterfaceImpl.Root = prefixExpression
|
||||
|
||||
return complexExpr(prefixExpression)
|
||||
return CustomExpression(Token(operator), expression)
|
||||
}
|
||||
|
||||
func (p *prefixExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
out.WriteString(p.operator)
|
||||
p.expression.serialize(statement, out, FallTrough(options)...)
|
||||
func newPostfixOperatorExpression(expression Expression, operator string) Expression {
|
||||
return CustomExpression(expression, Token(operator))
|
||||
}
|
||||
|
||||
// A postfix operator Expression
|
||||
type postfixOpExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
|
||||
expression Expression
|
||||
operator string
|
||||
}
|
||||
|
||||
func newPostfixOperatorExpression(expression Expression, operator string) *postfixOpExpression {
|
||||
postfixOpExpression := &postfixOpExpression{
|
||||
expression: expression,
|
||||
operator: operator,
|
||||
}
|
||||
|
||||
postfixOpExpression.ExpressionInterfaceImpl.Root = postfixOpExpression
|
||||
|
||||
return postfixOpExpression
|
||||
}
|
||||
|
||||
func (p *postfixOpExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
p.expression.serialize(statement, out, FallTrough(options)...)
|
||||
out.WriteString(p.operator)
|
||||
}
|
||||
|
||||
type betweenOperatorExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
|
||||
type betweenOperatorSerializer struct {
|
||||
expression Expression
|
||||
notBetween bool
|
||||
min Expression
|
||||
max Expression
|
||||
}
|
||||
|
||||
// NewBetweenOperatorExpression creates new BETWEEN operator expression
|
||||
func NewBetweenOperatorExpression(expression, min, max Expression, notBetween bool) BoolExpression {
|
||||
newBetweenOperator := &betweenOperatorExpression{
|
||||
expression: expression,
|
||||
notBetween: notBetween,
|
||||
min: min,
|
||||
max: max,
|
||||
}
|
||||
|
||||
newBetweenOperator.ExpressionInterfaceImpl.Root = newBetweenOperator
|
||||
|
||||
return BoolExp(complexExpr(newBetweenOperator))
|
||||
}
|
||||
|
||||
func (p *betweenOperatorExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
p.expression.serialize(statement, out, FallTrough(options)...)
|
||||
if p.notBetween {
|
||||
func (b *betweenOperatorSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
b.expression.serialize(statement, out, FallTrough(options)...)
|
||||
if b.notBetween {
|
||||
out.WriteString("NOT")
|
||||
}
|
||||
out.WriteString("BETWEEN")
|
||||
p.min.serialize(statement, out, FallTrough(options)...)
|
||||
b.min.serialize(statement, out, FallTrough(options)...)
|
||||
out.WriteString("AND")
|
||||
p.max.serialize(statement, out, FallTrough(options)...)
|
||||
b.max.serialize(statement, out, FallTrough(options)...)
|
||||
}
|
||||
|
||||
type customExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
parts []Serializer
|
||||
}
|
||||
|
||||
func CustomExpression(parts ...Serializer) Expression {
|
||||
ret := customExpression{
|
||||
parts: parts,
|
||||
}
|
||||
ret.ExpressionInterfaceImpl.Root = &ret
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (c *customExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
for _, expression := range c.parts {
|
||||
expression.serialize(statement, out, options...)
|
||||
}
|
||||
}
|
||||
|
||||
type complexExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
expressions Expression
|
||||
}
|
||||
|
||||
func complexExpr(expression Expression) Expression {
|
||||
complexExpression := &complexExpression{expressions: expression}
|
||||
complexExpression.ExpressionInterfaceImpl.Root = complexExpression
|
||||
|
||||
return complexExpression
|
||||
}
|
||||
|
||||
func (s *complexExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
s.expressions.serialize(statement, out, options...) // FallTrough here because complexExpression is just a wrapper
|
||||
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString(")")
|
||||
}
|
||||
}
|
||||
|
||||
func wrap(expressions ...Expression) Expression {
|
||||
return NewFunc("", expressions, nil)
|
||||
// NewBetweenOperatorExpression creates new BETWEEN operator expression
|
||||
func NewBetweenOperatorExpression(expression, min, max Expression, notBetween bool) BoolExpression {
|
||||
return BoolExp(newExpression(
|
||||
optionalWrap(&betweenOperatorSerializer{
|
||||
expression: expression,
|
||||
notBetween: notBetween,
|
||||
min: min,
|
||||
max: max,
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import (
|
|||
)
|
||||
|
||||
func TestExpressionIS_NULL(t *testing.T) {
|
||||
assertClauseSerialize(t, table2Col3.IS_NULL(), "table2.col3 IS NULL")
|
||||
assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NULL(), "(table2.col3 + table2.col3) IS NULL")
|
||||
assertClauseSerialize(t, table2Col3.IS_NULL(), "(table2.col3 IS NULL)")
|
||||
assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NULL(), "((table2.col3 + table2.col3) IS NULL)")
|
||||
}
|
||||
|
||||
func TestExpressionIS_NOT_NULL(t *testing.T) {
|
||||
assertClauseSerialize(t, table2Col3.IS_NOT_NULL(), "table2.col3 IS NOT NULL")
|
||||
assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NOT_NULL(), "(table2.col3 + table2.col3) IS NOT NULL")
|
||||
assertClauseSerialize(t, table2Col3.IS_NOT_NULL(), "(table2.col3 IS NOT NULL)")
|
||||
assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NOT_NULL(), "((table2.col3 + table2.col3) IS NOT NULL)")
|
||||
}
|
||||
|
||||
func TestExpressionIS_DISTINCT_FROM(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ 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...)
|
||||
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...)
|
||||
return newBoolExpressionListOperator("OR", expressions)
|
||||
}
|
||||
|
||||
// ------------------ Mathematical functions ---------------//
|
||||
|
|
@ -484,12 +484,12 @@ func REGEXP_LIKE(stringExp StringExpression, pattern StringExpression, matchType
|
|||
|
||||
// LOWER_BOUND returns range expressions lower bound. Returns null if range is empty or the requested bound is infinite.
|
||||
func LOWER_BOUND[T Expression](rangeExpression Range[T]) T {
|
||||
return rangeTypeCaster[T](rangeExpression, NewFunc("LOWER", []Expression{rangeExpression}, nil))
|
||||
return rangeTypeCaster[T](rangeExpression, newFunc("LOWER", []Expression{rangeExpression}))
|
||||
}
|
||||
|
||||
// UPPER_BOUND returns range expressions upper bound. Returns null if range is empty or the requested bound is infinite.
|
||||
func UPPER_BOUND[T Expression](rangeExpression Range[T]) T {
|
||||
return rangeTypeCaster[T](rangeExpression, NewFunc("UPPER", []Expression{rangeExpression}, nil))
|
||||
return rangeTypeCaster[T](rangeExpression, newFunc("UPPER", []Expression{rangeExpression}))
|
||||
}
|
||||
|
||||
func rangeTypeCaster[T Expression](rangeExpression Range[T], exp Expression) T {
|
||||
|
|
@ -543,7 +543,7 @@ func TO_CHAR(expression Expression, format StringExpression) StringExpression {
|
|||
|
||||
// TO_DATE converts string to date using format
|
||||
func TO_DATE(dateStr, format StringExpression) DateExpression {
|
||||
return NewDateFunc("TO_DATE", dateStr, format)
|
||||
return DateExp(newFunc("TO_DATE", []Expression{dateStr, format}))
|
||||
}
|
||||
|
||||
// TO_NUMBER converts string to numeric using format
|
||||
|
|
@ -560,74 +560,47 @@ func TO_TIMESTAMP(timestampzStr, format StringExpression) TimestampzExpression {
|
|||
|
||||
// EXTRACT extracts time component from time expression
|
||||
func EXTRACT(field string, from Expression) Expression {
|
||||
return CustomExpression(Token("EXTRACT("), Token(field), Token("FROM"), from, Token(")"))
|
||||
return AtomicCustomExpression(Token("EXTRACT("), Token(field), Token("FROM"), from, Token(")"))
|
||||
}
|
||||
|
||||
// CURRENT_DATE returns current date
|
||||
func CURRENT_DATE() DateExpression {
|
||||
dateFunc := NewDateFunc("CURRENT_DATE")
|
||||
dateFunc.noBrackets = true
|
||||
return dateFunc
|
||||
return DateKeyword("CURRENT_DATE")
|
||||
}
|
||||
|
||||
// CURRENT_TIME returns current time with time zone
|
||||
func CURRENT_TIME(precision ...int) TimezExpression {
|
||||
var timezFunc *timezFunc
|
||||
|
||||
if len(precision) > 0 {
|
||||
timezFunc = newTimezFunc("CURRENT_TIME", FixedLiteral(precision[0]))
|
||||
} else {
|
||||
timezFunc = newTimezFunc("CURRENT_TIME")
|
||||
return newTimezFunc("CURRENT_TIME", FixedLiteral(precision[0]))
|
||||
}
|
||||
|
||||
timezFunc.noBrackets = true
|
||||
|
||||
return timezFunc
|
||||
return TimezKeyword("CURRENT_TIME")
|
||||
}
|
||||
|
||||
// CURRENT_TIMESTAMP returns current timestamp with time zone
|
||||
func CURRENT_TIMESTAMP(precision ...int) TimestampzExpression {
|
||||
var timestampzFunc *timestampzFunc
|
||||
|
||||
if len(precision) > 0 {
|
||||
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP", FixedLiteral(precision[0]))
|
||||
} else {
|
||||
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP")
|
||||
return newTimestampzFunc("CURRENT_TIMESTAMP", FixedLiteral(precision[0]))
|
||||
}
|
||||
|
||||
timestampzFunc.noBrackets = true
|
||||
|
||||
return timestampzFunc
|
||||
return TimestampzKeyword("CURRENT_TIMESTAMP")
|
||||
}
|
||||
|
||||
// LOCALTIME returns local time of day using optional precision
|
||||
func LOCALTIME(precision ...int) TimeExpression {
|
||||
var timeFunc *timeFunc
|
||||
|
||||
if len(precision) > 0 {
|
||||
timeFunc = NewTimeFunc("LOCALTIME", FixedLiteral(precision[0]))
|
||||
} else {
|
||||
timeFunc = NewTimeFunc("LOCALTIME")
|
||||
return NewTimeFunc("LOCALTIME", FixedLiteral(precision[0]))
|
||||
}
|
||||
|
||||
timeFunc.noBrackets = true
|
||||
|
||||
return timeFunc
|
||||
return TimeKeyword("LOCALTIME")
|
||||
}
|
||||
|
||||
// LOCALTIMESTAMP returns current date and time using optional precision
|
||||
func LOCALTIMESTAMP(precision ...int) TimestampExpression {
|
||||
var timestampFunc *timestampFunc
|
||||
|
||||
if len(precision) > 0 {
|
||||
timestampFunc = NewTimestampFunc("LOCALTIMESTAMP", FixedLiteral(precision[0]))
|
||||
} else {
|
||||
timestampFunc = NewTimestampFunc("LOCALTIMESTAMP")
|
||||
return NewTimestampFunc("LOCALTIMESTAMP", FixedLiteral(precision[0]))
|
||||
}
|
||||
|
||||
timestampFunc.noBrackets = true
|
||||
|
||||
return timestampFunc
|
||||
return TimestampKeyword("LOCALTIMESTAMP")
|
||||
}
|
||||
|
||||
// NOW returns current date and time
|
||||
|
|
@ -641,74 +614,59 @@ func NOW() TimestampzExpression {
|
|||
func COALESCE(value Expression, values ...Expression) Expression {
|
||||
var allValues = []Expression{value}
|
||||
allValues = append(allValues, values...)
|
||||
return NewFunc("COALESCE", allValues, nil)
|
||||
return newFunc("COALESCE", allValues)
|
||||
}
|
||||
|
||||
// NULLIF function returns a null value if value1 equals value2; otherwise it returns value1.
|
||||
func NULLIF(value1, value2 Expression) Expression {
|
||||
return NewFunc("NULLIF", []Expression{value1, value2}, nil)
|
||||
return newFunc("NULLIF", []Expression{value1, value2})
|
||||
}
|
||||
|
||||
// GREATEST selects the largest value from a list of expressions
|
||||
func GREATEST(value Expression, values ...Expression) Expression {
|
||||
var allValues = []Expression{value}
|
||||
allValues = append(allValues, values...)
|
||||
return NewFunc("GREATEST", allValues, nil)
|
||||
return newFunc("GREATEST", allValues)
|
||||
}
|
||||
|
||||
// LEAST selects the smallest value from a list of expressions
|
||||
func LEAST(value Expression, values ...Expression) Expression {
|
||||
var allValues = []Expression{value}
|
||||
allValues = append(allValues, values...)
|
||||
return NewFunc("LEAST", allValues, nil)
|
||||
return newFunc("LEAST", allValues)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
|
||||
type funcExpressionImpl struct {
|
||||
ExpressionInterfaceImpl
|
||||
// newFunc creates new function with name and expressions parameters
|
||||
func newFunc(name string, expressions []Expression) Expression {
|
||||
return newExpression(&funcSerializer{
|
||||
name: name,
|
||||
parameters: expressions,
|
||||
})
|
||||
}
|
||||
|
||||
type funcSerializer struct {
|
||||
name string
|
||||
parameters parametersSerializer
|
||||
noBrackets bool
|
||||
}
|
||||
|
||||
// NewFunc creates new function with name and expressions parameters
|
||||
func NewFunc(name string, expressions []Expression, root Expression) *funcExpressionImpl {
|
||||
funcExp := &funcExpressionImpl{
|
||||
name: name,
|
||||
parameters: parametersSerializer(expressions),
|
||||
}
|
||||
|
||||
if root != nil {
|
||||
funcExp.ExpressionInterfaceImpl.Root = root
|
||||
} else {
|
||||
funcExp.ExpressionInterfaceImpl.Root = funcExp
|
||||
}
|
||||
|
||||
return funcExp
|
||||
}
|
||||
|
||||
func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
func (f *funcSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil {
|
||||
serializeOverrideFunc := serializeOverride(ExpressionListToSerializerList(f.parameters)...)
|
||||
serializeOverrideFunc := serializeOverride(ToSerializerList(f.parameters)...)
|
||||
serializeOverrideFunc(statement, out, FallTrough(options)...)
|
||||
return
|
||||
}
|
||||
|
||||
addBrackets := !f.noBrackets || len(f.parameters) > 0
|
||||
|
||||
if addBrackets {
|
||||
out.WriteString(f.name + "(")
|
||||
} else {
|
||||
out.WriteString(f.name)
|
||||
}
|
||||
out.WriteString(f.name + "(")
|
||||
|
||||
f.parameters.serialize(statement, out, options...)
|
||||
|
||||
if addBrackets {
|
||||
out.WriteString(")")
|
||||
}
|
||||
out.WriteString(")")
|
||||
}
|
||||
|
||||
func newBoolFunc(name string, expressions ...Expression) BoolExpression {
|
||||
return BoolExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
type parametersSerializer []Expression
|
||||
|
|
@ -730,208 +688,83 @@ func (p parametersSerializer) serialize(statement StatementType, out *SQLBuilder
|
|||
|
||||
// NewFloatWindowFunc creates new float function with name and expressions
|
||||
func newWindowFunc(name string, expressions ...Expression) windowExpression {
|
||||
newFun := NewFunc(name, expressions, nil)
|
||||
windowExpr := newWindowExpression(newFun)
|
||||
newFun.ExpressionInterfaceImpl.Root = windowExpr
|
||||
|
||||
return windowExpr
|
||||
}
|
||||
|
||||
type boolFunc struct {
|
||||
funcExpressionImpl
|
||||
boolInterfaceImpl
|
||||
}
|
||||
|
||||
func newBoolFunc(name string, expressions ...Expression) BoolExpression {
|
||||
boolFunc := &boolFunc{}
|
||||
|
||||
boolFunc.funcExpressionImpl = *NewFunc(name, expressions, boolFunc)
|
||||
boolFunc.boolInterfaceImpl.root = boolFunc
|
||||
boolFunc.ExpressionInterfaceImpl.Root = boolFunc
|
||||
|
||||
return boolFunc
|
||||
return newWindowExpression(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// NewFloatWindowFunc creates new float function with name and expressions
|
||||
func newBoolWindowFunc(name string, expressions ...Expression) boolWindowExpression {
|
||||
boolFunc := &boolFunc{}
|
||||
|
||||
boolFunc.funcExpressionImpl = *NewFunc(name, expressions, boolFunc)
|
||||
intWindowFunc := newBoolWindowExpression(boolFunc)
|
||||
boolFunc.boolInterfaceImpl.root = intWindowFunc
|
||||
boolFunc.ExpressionInterfaceImpl.Root = intWindowFunc
|
||||
|
||||
return intWindowFunc
|
||||
}
|
||||
|
||||
type floatFunc struct {
|
||||
funcExpressionImpl
|
||||
floatInterfaceImpl
|
||||
return newBoolWindowExpression(BoolExp(newFunc(name, expressions)))
|
||||
}
|
||||
|
||||
// NewFloatFunc creates new float function with name and expressions
|
||||
func NewFloatFunc(name string, expressions ...Expression) FloatExpression {
|
||||
floatFunc := &floatFunc{}
|
||||
|
||||
floatFunc.funcExpressionImpl = *NewFunc(name, expressions, floatFunc)
|
||||
floatFunc.floatInterfaceImpl.root = floatFunc
|
||||
|
||||
return floatFunc
|
||||
return FloatExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// NewFloatWindowFunc creates new float function with name and expressions
|
||||
func NewFloatWindowFunc(name string, expressions ...Expression) floatWindowExpression {
|
||||
floatFunc := &floatFunc{}
|
||||
|
||||
floatFunc.funcExpressionImpl = *NewFunc(name, expressions, floatFunc)
|
||||
floatWindowFunc := newFloatWindowExpression(floatFunc)
|
||||
floatFunc.floatInterfaceImpl.root = floatWindowFunc
|
||||
floatFunc.ExpressionInterfaceImpl.Root = floatWindowFunc
|
||||
|
||||
return floatWindowFunc
|
||||
}
|
||||
|
||||
type integerFunc struct {
|
||||
funcExpressionImpl
|
||||
integerInterfaceImpl
|
||||
return newFloatWindowExpression(FloatExp(newFunc(name, expressions)))
|
||||
}
|
||||
|
||||
func newIntegerFunc(name string, expressions ...Expression) IntegerExpression {
|
||||
intFunc := &integerFunc{}
|
||||
|
||||
intFunc.funcExpressionImpl = *NewFunc(name, expressions, intFunc)
|
||||
intFunc.integerInterfaceImpl.root = intFunc
|
||||
|
||||
return intFunc
|
||||
return IntExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// NewFloatWindowFunc creates new float function with name and expressions
|
||||
func newIntegerWindowFunc(name string, expressions ...Expression) integerWindowExpression {
|
||||
integerFunc := &integerFunc{}
|
||||
|
||||
integerFunc.funcExpressionImpl = *NewFunc(name, expressions, integerFunc)
|
||||
intWindowFunc := newIntegerWindowExpression(integerFunc)
|
||||
integerFunc.integerInterfaceImpl.root = intWindowFunc
|
||||
integerFunc.ExpressionInterfaceImpl.Root = intWindowFunc
|
||||
|
||||
return intWindowFunc
|
||||
}
|
||||
|
||||
type stringFunc struct {
|
||||
funcExpressionImpl
|
||||
stringInterfaceImpl
|
||||
return newIntegerWindowExpression(IntExp(newFunc(name, expressions)))
|
||||
}
|
||||
|
||||
// NewStringFunc creates new string function with name and expression parameters
|
||||
func NewStringFunc(name string, expressions ...Expression) StringExpression {
|
||||
stringFunc := &stringFunc{}
|
||||
|
||||
stringFunc.funcExpressionImpl = *NewFunc(name, expressions, stringFunc)
|
||||
stringFunc.stringInterfaceImpl.root = stringFunc
|
||||
|
||||
return stringFunc
|
||||
}
|
||||
|
||||
type dateFunc struct {
|
||||
funcExpressionImpl
|
||||
dateInterfaceImpl
|
||||
}
|
||||
|
||||
// NewDateFunc creates new date function with name and expression parameters
|
||||
func NewDateFunc(name string, expressions ...Expression) *dateFunc {
|
||||
dateFunc := &dateFunc{}
|
||||
|
||||
dateFunc.funcExpressionImpl = *NewFunc(name, expressions, dateFunc)
|
||||
dateFunc.dateInterfaceImpl.root = dateFunc
|
||||
|
||||
return dateFunc
|
||||
}
|
||||
|
||||
type timeFunc struct {
|
||||
funcExpressionImpl
|
||||
timeInterfaceImpl
|
||||
return StringExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// NewTimeFunc creates new time function with name and expression parameters
|
||||
func NewTimeFunc(name string, expressions ...Expression) *timeFunc {
|
||||
timeFun := &timeFunc{}
|
||||
|
||||
timeFun.funcExpressionImpl = *NewFunc(name, expressions, timeFun)
|
||||
timeFun.timeInterfaceImpl.root = timeFun
|
||||
|
||||
return timeFun
|
||||
func NewTimeFunc(name string, expressions ...Expression) TimeExpression {
|
||||
return TimeExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
type timezFunc struct {
|
||||
funcExpressionImpl
|
||||
timezInterfaceImpl
|
||||
}
|
||||
|
||||
func newTimezFunc(name string, expressions ...Expression) *timezFunc {
|
||||
timezFun := &timezFunc{}
|
||||
|
||||
timezFun.funcExpressionImpl = *NewFunc(name, expressions, timezFun)
|
||||
timezFun.timezInterfaceImpl.root = timezFun
|
||||
|
||||
return timezFun
|
||||
}
|
||||
|
||||
type timestampFunc struct {
|
||||
funcExpressionImpl
|
||||
timestampInterfaceImpl
|
||||
func newTimezFunc(name string, expressions ...Expression) TimezExpression {
|
||||
return TimezExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// NewTimestampFunc creates new timestamp function with name and expressions
|
||||
func NewTimestampFunc(name string, expressions ...Expression) *timestampFunc {
|
||||
timestampFunc := ×tampFunc{}
|
||||
|
||||
timestampFunc.funcExpressionImpl = *NewFunc(name, expressions, timestampFunc)
|
||||
timestampFunc.timestampInterfaceImpl.root = timestampFunc
|
||||
|
||||
return timestampFunc
|
||||
func NewTimestampFunc(name string, expressions ...Expression) TimestampExpression {
|
||||
return TimestampExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
type timestampzFunc struct {
|
||||
funcExpressionImpl
|
||||
timestampzInterfaceImpl
|
||||
}
|
||||
|
||||
func newTimestampzFunc(name string, expressions ...Expression) *timestampzFunc {
|
||||
timestampzFunc := ×tampzFunc{}
|
||||
|
||||
timestampzFunc.funcExpressionImpl = *NewFunc(name, expressions, timestampzFunc)
|
||||
timestampzFunc.timestampzInterfaceImpl.root = timestampzFunc
|
||||
|
||||
return timestampzFunc
|
||||
func newTimestampzFunc(name string, expressions ...Expression) TimestampzExpression {
|
||||
return TimestampzExp(newFunc(name, expressions))
|
||||
}
|
||||
|
||||
// Func can be used to call custom or unsupported database functions.
|
||||
func Func(name string, expressions ...Expression) Expression {
|
||||
return NewFunc(name, expressions, nil)
|
||||
return newFunc(name, expressions)
|
||||
}
|
||||
|
||||
func NumRange(lowNum, highNum NumericExpression, bounds ...StringExpression) Range[NumericExpression] {
|
||||
return NumRangeExp(NewFunc("numrange", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||
return NumRangeExp(newFunc("numrange", rangeFuncParamCombiner(lowNum, highNum, bounds...)))
|
||||
}
|
||||
|
||||
func Int4Range(lowNum, highNum IntegerExpression, bounds ...StringExpression) Range[Int4Expression] {
|
||||
return Int4RangeExp(NewFunc("int4range", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||
return Int4RangeExp(newFunc("int4range", rangeFuncParamCombiner(lowNum, highNum, bounds...)))
|
||||
}
|
||||
|
||||
func Int8Range(lowNum, highNum Int8Expression, bounds ...StringExpression) Range[Int8Expression] {
|
||||
return Int8RangeExp(NewFunc("int8range", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||
return Int8RangeExp(newFunc("int8range", rangeFuncParamCombiner(lowNum, highNum, bounds...)))
|
||||
}
|
||||
|
||||
func TsRange(lowTs, highTs TimestampExpression, bounds ...StringExpression) Range[TimestampExpression] {
|
||||
return TsRangeExp(NewFunc("tsrange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||
return TsRangeExp(newFunc("tsrange", rangeFuncParamCombiner(lowTs, highTs, bounds...)))
|
||||
}
|
||||
|
||||
func TstzRange(lowTs, highTs TimestampzExpression, bounds ...StringExpression) Range[TimestampzExpression] {
|
||||
return TstzRangeExp(NewFunc("tstzrange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||
return TstzRangeExp(newFunc("tstzrange", rangeFuncParamCombiner(lowTs, highTs, bounds...)))
|
||||
}
|
||||
|
||||
func DateRange(lowTs, highTs DateExpression, bounds ...StringExpression) Range[DateExpression] {
|
||||
return DateRangeExp(NewFunc("daterange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||
return DateRangeExp(newFunc("daterange", rangeFuncParamCombiner(lowTs, highTs, bounds...)))
|
||||
}
|
||||
|
||||
func rangeFuncParamCombiner(low, high Expression, bounds ...StringExpression) []Expression {
|
||||
|
|
@ -941,3 +774,23 @@ func rangeFuncParamCombiner(low, high Expression, bounds ...StringExpression) []
|
|||
}
|
||||
return exp
|
||||
}
|
||||
|
||||
func TimeKeyword(name string) TimeExpression {
|
||||
return TimeExp(newExpression(Keyword(name)))
|
||||
}
|
||||
|
||||
func TimezKeyword(name string) TimezExpression {
|
||||
return TimezExp(newExpression(Keyword(name)))
|
||||
}
|
||||
|
||||
func TimestampKeyword(name string) TimestampExpression {
|
||||
return TimestampExp(newExpression(Keyword(name)))
|
||||
}
|
||||
|
||||
func TimestampzKeyword(name string) TimestampzExpression {
|
||||
return TimestampzExp(newExpression(Keyword(name)))
|
||||
}
|
||||
|
||||
func DateKeyword(name string) DateExpression {
|
||||
return DateExp(newExpression(Keyword(name)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
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.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))),
|
||||
`(
|
||||
|
|
@ -17,7 +17,7 @@ func TestAND(t *testing.T) {
|
|||
|
||||
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.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))),
|
||||
`(
|
||||
|
|
@ -205,7 +205,7 @@ func TestFunc(t *testing.T) {
|
|||
|
||||
func Test_rangePointCaster(t *testing.T) {
|
||||
mainRange := Int8Range(Int8(10), Int8(12))
|
||||
exp := NewFunc("UPPER", []Expression{mainRange}, nil)
|
||||
exp := newFunc("UPPER", []Expression{mainRange})
|
||||
|
||||
got := rangeTypeCaster(mainRange, exp)
|
||||
_, ok := got.(IntegerExpression)
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func newRowExpression(name string, dialect Dialect, expressions ...Expression) R
|
|||
ret := &rowExpressionWrapper{}
|
||||
ret.rowInterfaceImpl.root = ret
|
||||
|
||||
ret.Expression = NewFunc(name, expressions, ret)
|
||||
ret.Expression = newFunc(name, expressions)
|
||||
ret.dialect = dialect
|
||||
ret.expressions = expressions
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package jet
|
||||
|
||||
import "slices"
|
||||
|
||||
// SerializeOption type
|
||||
type SerializeOption int
|
||||
|
||||
|
|
@ -73,6 +75,12 @@ func FallTrough(options []SerializeOption) []SerializeOption {
|
|||
return ret
|
||||
}
|
||||
|
||||
func without(options []SerializeOption, option SerializeOption) []SerializeOption {
|
||||
return slices.DeleteFunc(options, func(elem SerializeOption) bool {
|
||||
return elem == option
|
||||
})
|
||||
}
|
||||
|
||||
// ListSerializer serializes list of serializers with separator
|
||||
type ListSerializer struct {
|
||||
Serializers []Serializer
|
||||
|
|
@ -109,3 +117,68 @@ type Token string
|
|||
func (t Token) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
out.WriteString(string(t))
|
||||
}
|
||||
|
||||
// CustomExpression creates new custom expression. When serialized may require parentheses
|
||||
// depending on context.
|
||||
func CustomExpression(parts ...Serializer) Expression {
|
||||
return newExpression(optionalWrap(&customSerializer{
|
||||
parts: parts,
|
||||
}))
|
||||
}
|
||||
|
||||
type customSerializer struct {
|
||||
parts []Serializer
|
||||
}
|
||||
|
||||
func (c *customSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
for _, expression := range c.parts {
|
||||
expression.serialize(statement, out, options...)
|
||||
}
|
||||
}
|
||||
|
||||
type optionalWrapSerializer struct {
|
||||
serializer []Serializer
|
||||
}
|
||||
|
||||
func optionalWrap(serializer ...Serializer) Serializer {
|
||||
return &optionalWrapSerializer{serializer: serializer}
|
||||
}
|
||||
|
||||
func (s *optionalWrapSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
for _, ser := range s.serializer {
|
||||
ser.serialize(statement, out, without(options, NoWrap)...)
|
||||
}
|
||||
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString(")")
|
||||
}
|
||||
}
|
||||
|
||||
// AtomicCustomExpression creates new custom expression. When serialized does not require parentheses.
|
||||
func AtomicCustomExpression(parts ...Serializer) Expression {
|
||||
return newExpression(noWrap(&customSerializer{
|
||||
parts: parts,
|
||||
}))
|
||||
}
|
||||
|
||||
type noWrapSerializer struct {
|
||||
serializer []Serializer
|
||||
}
|
||||
|
||||
func noWrap(serializer ...Serializer) Serializer {
|
||||
return &noWrapSerializer{serializer: serializer}
|
||||
}
|
||||
|
||||
func (s *noWrapSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
for _, ser := range s.serializer {
|
||||
ser.serialize(statement, out, without(options, NoWrap)...)
|
||||
}
|
||||
}
|
||||
|
||||
func wrap(expressions ...Expression) Expression {
|
||||
return newFunc("", expressions)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,12 +121,12 @@ func SerializeColumnExpressionNames(columns []ColumnExpression, out *SQLBuilder)
|
|||
}
|
||||
}
|
||||
|
||||
// ExpressionListToSerializerList converts list of expressions to list of serializers
|
||||
func ExpressionListToSerializerList(expressions []Expression) []Serializer {
|
||||
var ret []Serializer
|
||||
// ToSerializerList converts list of expressions to list of serializers
|
||||
func ToSerializerList[T Serializer](elems []T) []Serializer {
|
||||
ret := make([]Serializer, len(elems))
|
||||
|
||||
for _, expr := range expressions {
|
||||
ret = append(ret, expr)
|
||||
for i, ser := range elems {
|
||||
ret[i] = ser
|
||||
}
|
||||
|
||||
return ret
|
||||
|
|
@ -134,10 +134,10 @@ func ExpressionListToSerializerList(expressions []Expression) []Serializer {
|
|||
|
||||
// ToExpressionList converts list of any expressions to list of expressions
|
||||
func ToExpressionList[T Expression](expressions []T) []Expression {
|
||||
var ret []Expression
|
||||
ret := make([]Expression, len(expressions))
|
||||
|
||||
for _, expression := range expressions {
|
||||
ret = append(ret, expression)
|
||||
for i, expr := range expressions {
|
||||
ret[i] = expr
|
||||
}
|
||||
|
||||
return ret
|
||||
|
|
@ -145,10 +145,10 @@ func ToExpressionList[T Expression](expressions []T) []Expression {
|
|||
|
||||
// ColumnListToProjectionList func
|
||||
func ColumnListToProjectionList(columns []ColumnExpression) []Projection {
|
||||
var ret []Projection
|
||||
ret := make([]Projection, len(columns))
|
||||
|
||||
for _, column := range columns {
|
||||
ret = append(ret, column)
|
||||
for i, column := range columns {
|
||||
ret[i] = column
|
||||
}
|
||||
|
||||
return ret
|
||||
|
|
@ -252,11 +252,11 @@ func OptionalOrDefaultString(defaultStr string, str ...string) string {
|
|||
return defaultStr
|
||||
}
|
||||
|
||||
// OptionalOrDefaultExpression will return first value from variable argument list expression or
|
||||
// OptionalOrDefault will return first value from variable argument list expression or
|
||||
// defaultExpression if variable argument list is empty
|
||||
func OptionalOrDefaultExpression(defaultExpression Expression, expression ...Expression) Expression {
|
||||
if len(expression) > 0 {
|
||||
return expression[0]
|
||||
func OptionalOrDefault(expressions []Expression, defaultExpression Expression) Expression {
|
||||
if len(expressions) > 0 {
|
||||
return expressions[0]
|
||||
}
|
||||
|
||||
return defaultExpression
|
||||
|
|
@ -292,3 +292,13 @@ func joinAlias(tableAlias, columnAlias string) string {
|
|||
}
|
||||
return strings.TrimRight(tableAlias, ".*") + "." + columnAlias
|
||||
}
|
||||
|
||||
func optional[T any](value []T) T {
|
||||
if len(value) > 0 {
|
||||
return value[0]
|
||||
}
|
||||
|
||||
var def T
|
||||
|
||||
return def
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ func TestOptionalOrDefaultString(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOptionalOrDefaultExpression(t *testing.T) {
|
||||
defaultExpression := table2ColFloat
|
||||
defaultExpression := []Expression{table2ColFloat}
|
||||
optionalExpression := table1Col1
|
||||
|
||||
require.Equal(t, OptionalOrDefaultExpression(defaultExpression), defaultExpression)
|
||||
require.Equal(t, OptionalOrDefaultExpression(defaultExpression, optionalExpression), optionalExpression)
|
||||
require.Equal(t, OptionalOrDefault(defaultExpression, nil), table2ColFloat)
|
||||
require.Equal(t, OptionalOrDefault(defaultExpression, optionalExpression), table2ColFloat)
|
||||
require.Equal(t, OptionalOrDefault(nil, optionalExpression), table1Col1)
|
||||
}
|
||||
|
||||
func TestJoinAlias(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,13 @@ type windowExpression interface {
|
|||
OVER(window ...Window) Expression
|
||||
}
|
||||
|
||||
func newWindowExpression(Exp Expression) windowExpression {
|
||||
func newWindowExpression(exp Expression) windowExpression {
|
||||
newExp := &windowExpressionImpl{
|
||||
Expression: Exp,
|
||||
Expression: exp,
|
||||
}
|
||||
|
||||
newExp.commonWindowImpl.expression = Exp
|
||||
newExp.commonWindowImpl.expression = exp
|
||||
exp.setRoot(newExp)
|
||||
|
||||
return newExp
|
||||
}
|
||||
|
|
@ -65,6 +66,7 @@ func newFloatWindowExpression(floatExp FloatExpression) floatWindowExpression {
|
|||
}
|
||||
|
||||
newExp.commonWindowImpl.expression = floatExp
|
||||
floatExp.setRoot(newExp)
|
||||
|
||||
return newExp
|
||||
}
|
||||
|
|
@ -96,6 +98,7 @@ func newIntegerWindowExpression(intExp IntegerExpression) integerWindowExpressio
|
|||
}
|
||||
|
||||
newExp.commonWindowImpl.expression = intExp
|
||||
intExp.setRoot(newExp)
|
||||
|
||||
return newExp
|
||||
}
|
||||
|
|
@ -127,6 +130,7 @@ func newBoolWindowExpression(boolExp BoolExpression) boolWindowExpression {
|
|||
}
|
||||
|
||||
newExp.commonWindowImpl.expression = boolExp
|
||||
boolExp.setRoot(newExp)
|
||||
|
||||
return newExp
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue