Simplify literal expressions.

This commit is contained in:
go-jet 2026-02-02 13:21:35 +01:00
parent 4995a90483
commit 0e495a279e
26 changed files with 233 additions and 616 deletions

View file

@ -1,53 +0,0 @@
package jet
// Cast interface
type Cast interface {
AS(castType string) Expression
}
type castImpl struct {
expression Expression
}
// NewCastImpl creates new generic cast
func NewCastImpl(expression Expression) Cast {
castImpl := castImpl{
expression: expression,
}
return &castImpl
}
func (b *castImpl) AS(castType string) Expression {
castExp := &castExpression{
expression: b.expression,
cast: string(castType),
}
castExp.ExpressionInterfaceImpl.Root = castExp
return castExp
}
type castExpression struct {
ExpressionInterfaceImpl
expression Expression
cast string
}
func (b *castExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
expression := b.expression
castType := b.cast
if castOverride := out.Dialect.OperatorSerializeOverride("CAST"); castOverride != nil {
castOverride(expression, String(castType))(statement, out, FallTrough(options)...)
return
}
out.WriteString("CAST(")
expression.serialize(statement, out, FallTrough(options)...)
out.WriteString("AS")
out.WriteString(castType + ")")
}

View file

@ -1,11 +0,0 @@
package jet
import (
"testing"
)
func TestCastAS(t *testing.T) {
assertClauseSerialize(t, NewCastImpl(Int(1)).AS("boolean"), "CAST($1 AS boolean)", int64(1))
assertClauseSerialize(t, NewCastImpl(table2Col3).AS("real"), "CAST(table2.col3 AS real)")
assertClauseSerialize(t, NewCastImpl(table2Col3.ADD(table2Col3)).AS("integer"), "CAST((table2.col3 + table2.col3) AS integer)")
}

View file

@ -18,6 +18,7 @@ type Dialect interface {
SerializeOrderBy() func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
ValuesDefaultColumnName(index int) string
JsonValueEncode(expr Expression) Expression
RegexpLike(str StringExpression, not bool, pattern StringExpression, caseSensitive bool) SerializerFunc
}
// SerializerFunc func
@ -43,6 +44,7 @@ type DialectParams struct {
SerializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
ValuesDefaultColumnName func(index int) string
JsonValueEncode func(expr Expression) Expression
RegexpLike func(str StringExpression, not bool, pattern StringExpression, caseSensitive bool) SerializerFunc
}
// NewDialect creates new dialect with params
@ -60,6 +62,7 @@ func NewDialect(params DialectParams) Dialect {
serializeOrderBy: params.SerializeOrderBy,
valuesDefaultColumnName: params.ValuesDefaultColumnName,
jsonValueEncode: params.JsonValueEncode,
regexpLike: params.RegexpLike,
}
}
@ -76,6 +79,7 @@ type dialectImpl struct {
serializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
valuesDefaultColumnName func(index int) string
jsonValueEncode func(expr Expression) Expression
regexpLike func(str StringExpression, not bool, pattern StringExpression, caseSensitive bool) SerializerFunc
}
func (d *dialectImpl) Name() string {
@ -133,6 +137,21 @@ func (d *dialectImpl) JsonValueEncode(expr Expression) Expression {
return d.jsonValueEncode(expr)
}
func (d *dialectImpl) RegexpLike(str StringExpression, not bool, pattern StringExpression, caseSensitive bool) SerializerFunc {
if d.regexpLike != nil {
return d.regexpLike(str, not, pattern, caseSensitive)
}
return func(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
str.serialize(statement, out, FallTrough(options)...)
if not {
out.WriteString("NOT")
}
out.WriteString("REGEXP")
pattern.serialize(statement, out, FallTrough(options)...)
}
}
func arrayOfStringsToMapOfStrings(arr []string) map[string]bool {
ret := map[string]bool{}
for _, elem := range arr {

View file

@ -141,24 +141,27 @@ type binaryOperatorSerializer struct {
}
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)...)
} else {
c.lhs.serialize(statement, out, FallTrough(options)...)
out.WriteString(c.operator)
c.rhs.serialize(statement, out, FallTrough(options)...)
}
optionalWrap(out, options, func(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)...)
} else {
c.lhs.serialize(statement, out, FallTrough(options)...)
out.WriteString(c.operator)
c.rhs.serialize(statement, out, FallTrough(options)...)
}
})
}
// NewBinaryOperatorExpression creates new binaryOperatorExpression
func NewBinaryOperatorExpression(lhs, rhs Serializer, operator string, additionalParam ...Expression) Expression {
return newExpression(optionalWrap(&binaryOperatorSerializer{
return newExpression(&binaryOperatorSerializer{
lhs: lhs,
rhs: rhs,
additionalParam: OptionalOrDefault(additionalParam, nil),
operator: operator,
}))
})
}
type serializersWithOperator struct {
@ -226,24 +229,24 @@ type betweenOperatorSerializer struct {
}
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")
b.min.serialize(statement, out, FallTrough(options)...)
out.WriteString("AND")
b.max.serialize(statement, out, FallTrough(options)...)
optionalWrap(out, options, func(out *SQLBuilder, options []SerializeOption) {
b.expression.serialize(statement, out, FallTrough(options)...)
if b.notBetween {
out.WriteString("NOT")
}
out.WriteString("BETWEEN")
b.min.serialize(statement, out, FallTrough(options)...)
out.WriteString("AND")
b.max.serialize(statement, out, FallTrough(options)...)
})
}
// 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,
}),
))
return BoolExp(newExpression(&betweenOperatorSerializer{
expression: expression,
notBetween: notBetween,
min: min,
max: max,
}))
}

View file

@ -244,7 +244,7 @@ func leadLagImpl(name string, expr Expression, offsetAndDefault ...interface{})
defaultValue, ok = offsetAndDefault[1].(Expression)
if !ok {
defaultValue = literal(offsetAndDefault[1])
defaultValue = Literal(offsetAndDefault[1])
}
params = append(params, FixedLiteral(offset), defaultValue)

View file

@ -66,7 +66,7 @@ func TestIntExpressionPOW(t *testing.T) {
func TestIntExpressionBIT_NOT(t *testing.T) {
assertClauseSerialize(t, BIT_NOT(table2ColInt), "(~ table2.col_int)")
assertClauseSerialize(t, BIT_NOT(Int(11)), "(~ 11)")
assertClauseSerialize(t, BIT_NOT(Int(11)), "(~ $1)", int64(11))
}
func TestIntExpressionBIT_AND(t *testing.T) {

View file

@ -5,48 +5,12 @@ import (
"time"
)
// LiteralExpression is representation of an escaped literal
type LiteralExpression interface {
Expression
Value() interface{}
SetConstant(constant bool)
}
type literalExpressionImpl struct {
ExpressionInterfaceImpl
type literalSerializer struct {
value interface{}
constant bool
}
func literal(value interface{}, optionalConstant ...bool) *literalExpressionImpl {
exp := literalExpressionImpl{value: value}
if len(optionalConstant) > 0 {
exp.constant = optionalConstant[0]
}
exp.ExpressionInterfaceImpl.Root = &exp
return &exp
}
// Literal is injected directly to SQL query, and does not appear in parametrized argument list.
func Literal(value interface{}) *literalExpressionImpl {
exp := literal(value)
return exp
}
// FixedLiteral is injected directly to SQL query, and does not appear in parametrized argument list.
func FixedLiteral(value interface{}) *literalExpressionImpl {
exp := literal(value)
exp.constant = true
return exp
}
func (l *literalExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
func (l *literalSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if l.constant {
out.insertConstantArgument(l.value)
} else {
@ -54,260 +18,145 @@ func (l *literalExpressionImpl) serialize(statement StatementType, out *SQLBuild
}
}
func (l *literalExpressionImpl) Value() interface{} {
return l.value
// Literal is injected directly to SQL query, and does not appear in parametrized argument list.
func Literal(value interface{}) Expression {
return newExpression(&literalSerializer{
value: value,
constant: false,
})
}
func (l *literalExpressionImpl) SetConstant(constant bool) {
l.constant = constant
}
type integerLiteralExpression struct {
literalExpressionImpl
integerInterfaceImpl
}
func intLiteral(value interface{}) IntegerExpression {
numLiteral := &integerLiteralExpression{}
numLiteral.literalExpressionImpl = *literal(value)
numLiteral.literalExpressionImpl.Root = numLiteral
numLiteral.integerInterfaceImpl.root = numLiteral
return numLiteral
// FixedLiteral is injected directly to SQL query, and does not appear in parametrized argument list.
func FixedLiteral(value interface{}) Expression {
return newExpression(&literalSerializer{
value: value,
constant: true,
})
}
// Int creates a new 64 bit signed integer literal
func Int(value int64) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Int8 creates a new 8 bit signed integer literal
func Int8(value int8) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Int16 creates a new 16 bit signed integer literal
func Int16(value int16) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Int32 creates a new 32 bit signed integer literal
func Int32(value int32) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Uint8 creates a new 8 bit unsigned integer literal
func Uint8(value uint8) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Uint16 creates a new 16 bit unsigned integer literal
func Uint16(value uint16) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Uint32 creates a new 32 bit unsigned integer literal
func Uint32(value uint32) IntegerExpression {
return intLiteral(value)
return IntExp(Literal(value))
}
// Uint64 creates a new 64 bit unsigned integer literal
func Uint64(value uint64) IntegerExpression {
return intLiteral(value)
}
// ---------------------------------------------------//
type boolLiteralExpression struct {
boolInterfaceImpl
literalExpressionImpl
return IntExp(Literal(value))
}
// Bool creates new bool literal expression
func Bool(value bool) BoolExpression {
boolLiteralExpression := boolLiteralExpression{}
boolLiteralExpression.literalExpressionImpl = *literal(value)
boolLiteralExpression.boolInterfaceImpl.root = &boolLiteralExpression
return &boolLiteralExpression
}
// ---------------------------------------------------//
type floatLiteral struct {
floatInterfaceImpl
literalExpressionImpl
return BoolExp(Literal(value))
}
// Float creates new float literal from float64 value
func Float(value float64) FloatExpression {
floatLiteral := floatLiteral{}
floatLiteral.literalExpressionImpl = *literal(value)
floatLiteral.floatInterfaceImpl.root = &floatLiteral
return &floatLiteral
return FloatExp(Literal(value))
}
// Decimal creates new float literal from string value
func Decimal(value string) FloatExpression {
floatLiteral := floatLiteral{}
floatLiteral.literalExpressionImpl = *literal(value)
floatLiteral.floatInterfaceImpl.root = &floatLiteral
return &floatLiteral
}
// ---------------------------------------------------//
type stringLiteral struct {
stringInterfaceImpl
literalExpressionImpl
return FloatExp(Literal(value))
}
// String creates new string literal expression
func String(value string) StringExpression {
stringLiteral := stringLiteral{}
stringLiteral.literalExpressionImpl = *literal(value)
stringLiteral.stringInterfaceImpl.root = &stringLiteral
return &stringLiteral
}
//---------------------------------------------------//
type timeLiteral struct {
timeInterfaceImpl
literalExpressionImpl
return StringExp(Literal(value))
}
// Time creates new time literal expression
func Time(hour, minute, second int, nanoseconds ...time.Duration) TimeExpression {
timeLiteral := &timeLiteral{}
timeStr := fmt.Sprintf("%02d:%02d:%02d", hour, minute, second)
timeStr += formatNanoseconds(nanoseconds...)
timeLiteral.literalExpressionImpl = *literal(timeStr)
timeLiteral.timeInterfaceImpl.root = timeLiteral
return timeLiteral
return TimeExp(Literal(timeStr))
}
// TimeT creates new time literal expression from time.Time object
func TimeT(t time.Time) TimeExpression {
timeLiteral := &timeLiteral{}
timeLiteral.literalExpressionImpl = *literal(t)
timeLiteral.timeInterfaceImpl.root = timeLiteral
return timeLiteral
}
//---------------------------------------------------//
type timezLiteral struct {
timezInterfaceImpl
literalExpressionImpl
return TimeExp(Literal(t))
}
// Timez creates new time with time zone literal expression
func Timez(hour, minute, second int, nanoseconds time.Duration, timezone string) TimezExpression {
timezLiteral := timezLiteral{}
timeStr := fmt.Sprintf("%02d:%02d:%02d", hour, minute, second)
timeStr += formatNanoseconds(nanoseconds)
timeStr += " " + timezone
timezLiteral.literalExpressionImpl = *literal(timeStr)
return TimezExp(literal(timeStr))
return TimezExp(Literal(timeStr))
}
// TimezT creates new time with time zone literal expression from time.Time object
func TimezT(t time.Time) TimezExpression {
timeLiteral := &timezLiteral{}
timeLiteral.literalExpressionImpl = *literal(t)
timeLiteral.timezInterfaceImpl.root = timeLiteral
return timeLiteral
}
//---------------------------------------------------//
type timestampLiteral struct {
timestampInterfaceImpl
literalExpressionImpl
return TimezExp(Literal(t))
}
// Timestamp creates new timestamp literal expression
func Timestamp(year int, month time.Month, day, hour, minute, second int, nanoseconds ...time.Duration) TimestampExpression {
timestamp := &timestampLiteral{}
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
timeStr += formatNanoseconds(nanoseconds...)
timestamp.literalExpressionImpl = *literal(timeStr)
timestamp.timestampInterfaceImpl.root = timestamp
return timestamp
return TimestampExp(Literal(timeStr))
}
// TimestampT creates new timestamp literal expression from time.Time object
func TimestampT(t time.Time) TimestampExpression {
timestamp := &timestampLiteral{}
timestamp.literalExpressionImpl = *literal(t)
timestamp.timestampInterfaceImpl.root = timestamp
return timestamp
}
//---------------------------------------------------//
type timestampzLiteral struct {
timestampzInterfaceImpl
literalExpressionImpl
return TimestampExp(Literal(t))
}
// Timestampz creates new timestamp with time zone literal expression
func Timestampz(year int, month time.Month, day, hour, minute, second int, nanoseconds time.Duration, timezone string) TimestampzExpression {
timestamp := &timestampzLiteral{}
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
timeStr += formatNanoseconds(nanoseconds)
timeStr += " " + timezone
timestamp.literalExpressionImpl = *literal(timeStr)
timestamp.timestampzInterfaceImpl.root = timestamp
return timestamp
return TimestampzExp(Literal(timeStr))
}
// TimestampzT creates new timestamp literal expression from time.Time object
func TimestampzT(t time.Time) TimestampzExpression {
timestamp := &timestampzLiteral{}
timestamp.literalExpressionImpl = *literal(t)
timestamp.timestampzInterfaceImpl.root = timestamp
return timestamp
}
//---------------------------------------------------//
type dateLiteral struct {
dateInterfaceImpl
literalExpressionImpl
return TimestampzExp(Literal(t))
}
// Date creates new date literal expression
func Date(year int, month time.Month, day int) DateExpression {
dateLiteral := &dateLiteral{}
timeStr := fmt.Sprintf("%04d-%02d-%02d", year, month, day)
dateLiteral.literalExpressionImpl = *literal(timeStr)
dateLiteral.dateInterfaceImpl.root = dateLiteral
return dateLiteral
return DateExp(Literal(timeStr))
}
// DateT creates new date literal expression from time.Time object
func DateT(t time.Time) DateExpression {
dateLiteral := &dateLiteral{}
dateLiteral.literalExpressionImpl = *literal(t)
dateLiteral.dateInterfaceImpl.root = dateLiteral
return dateLiteral
return DateExp(Literal(t))
}
func formatNanoseconds(nanoseconds ...time.Duration) string {
@ -330,86 +179,35 @@ func formatNanoseconds(nanoseconds ...time.Duration) string {
var (
// NULL is jet equivalent of SQL NULL
NULL = newNullLiteral()
NULL = newExpression(Keyword("NULL"))
// STAR is jet equivalent of SQL *
STAR = newStarLiteral()
STAR = newExpression(Keyword("*"))
// PLUS_INFINITY is jet equivalent for sql infinity
PLUS_INFINITY = String("infinity")
// MINUS_INFINITY is jet equivalent for sql -infinity
MINUS_INFINITY = String("-infinity")
)
type nullLiteral struct {
ExpressionInterfaceImpl
}
func newNullLiteral() Expression {
nullExpression := &nullLiteral{}
nullExpression.ExpressionInterfaceImpl.Root = nullExpression
return nullExpression
}
func (n *nullLiteral) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString("NULL")
}
// --------------------------------------------------//
type starLiteral struct {
ExpressionInterfaceImpl
}
func newStarLiteral() Expression {
starExpression := &starLiteral{}
starExpression.ExpressionInterfaceImpl.Root = starExpression
return starExpression
}
func (n *starLiteral) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString("*")
}
//---------------------------------------------------//
type rawExpression struct {
ExpressionInterfaceImpl
type rawSerializer struct {
Raw string
NamedArgument map[string]interface{}
noWrap bool
}
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if !n.noWrap && !contains(options, NoWrap) {
out.WriteByte('(')
}
out.insertRawQuery(n.Raw, n.NamedArgument)
if !n.noWrap && !contains(options, NoWrap) {
out.WriteByte(')')
}
func (n *rawSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
optionalWrap(out, options, func(out *SQLBuilder, options []SerializeOption) {
out.insertRawQuery(n.Raw, n.NamedArgument)
})
}
// Raw can be used for any unsupported functions, operators or expressions.
// For example: Raw("current_database()")
func Raw(raw string, namedArgs ...map[string]interface{}) Expression {
var namedArguments map[string]interface{}
if len(namedArgs) > 0 {
namedArguments = namedArgs[0]
}
rawExp := &rawExpression{
return newExpression(&rawSerializer{
Raw: raw,
NamedArgument: namedArguments,
}
rawExp.ExpressionInterfaceImpl.Root = rawExp
return rawExp
NamedArgument: singleOptional(namedArgs),
})
}
// RawBool helper that for raw string boolean expressions

View file

@ -16,9 +16,6 @@ func NOT(exp BoolExpression) BoolExpression {
// BIT_NOT inverts every bit in integer expression result
func BIT_NOT(expr IntegerExpression) IntegerExpression {
if literalExp, ok := expr.(LiteralExpression); ok {
literalExp.SetConstant(true)
}
return newPrefixIntegerOperatorExpression(expr, "~")
}
@ -131,10 +128,8 @@ type caseOperatorImpl struct {
// CASE create CASE operator with optional list of expressions
func CASE(expression ...Expression) CaseOperator {
caseExp := &caseOperatorImpl{}
if len(expression) > 0 {
caseExp.expression = expression[0]
caseExp := &caseOperatorImpl{
expression: singleOptional(expression),
}
caseExp.ExpressionInterfaceImpl.Root = caseExp

View file

@ -34,25 +34,20 @@ func newOrderSetAggregateFunction(name string, fraction FloatExpression) *OrderS
// WITHIN_GROUP_ORDER_BY specifies ordered set of aggregated argument values
func (p *OrderSetAggregateFunc) WITHIN_GROUP_ORDER_BY(orderBy OrderByClause) Expression {
p.orderBy = ORDER_BY(orderBy)
return newOrderSetAggregateFuncExpression(*p)
return newOrderSetAggregateFuncExpression(p)
}
func newOrderSetAggregateFuncExpression(aggFunc OrderSetAggregateFunc) *orderSetAggregateFuncExpression {
ret := &orderSetAggregateFuncExpression{
func newOrderSetAggregateFuncExpression(aggFunc *OrderSetAggregateFunc) Expression {
return newExpression(&orderSetAggregateFuncSerializer{
OrderSetAggregateFunc: aggFunc,
}
ret.ExpressionInterfaceImpl.Root = ret
return ret
})
}
type orderSetAggregateFuncExpression struct {
ExpressionInterfaceImpl
OrderSetAggregateFunc
type orderSetAggregateFuncSerializer struct {
*OrderSetAggregateFunc
}
func (p *orderSetAggregateFuncExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
func (p *orderSetAggregateFuncSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(p.name)
if p.fraction != nil {

View file

@ -15,11 +15,8 @@ func RawStatement(dialect Dialect, rawQuery string, namedArgument ...map[string]
statementType: "",
root: nil,
},
RawQuery: rawQuery,
}
if len(namedArgument) > 0 {
newRawStatement.NamedArguments = namedArgument[0]
RawQuery: rawQuery,
NamedArguments: singleOptional(namedArgument),
}
newRawStatement.root = &newRawStatement

View file

@ -121,64 +121,50 @@ func (t Token) serialize(statement StatementType, out *SQLBuilder, options ...Se
// CustomExpression creates new custom expression. When serialized may require parentheses
// depending on context.
func CustomExpression(parts ...Serializer) Expression {
return newExpression(optionalWrap(&customSerializer{
return newExpression(&customSerializer{
parts: parts,
}))
})
}
// AtomicCustomExpression creates new custom expression. When serialized does not require parentheses.
func AtomicCustomExpression(parts ...Serializer) Expression {
return newExpression(&customSerializer{
parts: parts,
atomic: true,
})
}
type customSerializer struct {
parts []Serializer
parts []Serializer
atomic bool
}
func (c *customSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
for _, expression := range c.parts {
expression.serialize(statement, out, options...)
if c.atomic {
for _, expr := range c.parts {
expr.serialize(statement, out, without(options, NoWrap)...)
}
} else {
optionalWrap(out, options, func(out *SQLBuilder, options []SerializeOption) {
for _, expr := range c.parts {
expr.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) {
func optionalWrap(out *SQLBuilder, options []SerializeOption, ser func(out *SQLBuilder, options []SerializeOption)) {
if !contains(options, NoWrap) {
out.WriteString("(")
}
for _, ser := range s.serializer {
ser.serialize(statement, out, without(options, NoWrap)...)
}
ser(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)
}

View file

@ -85,11 +85,33 @@ func (s *stringInterfaceImpl) NOT_LIKE(pattern StringExpression) BoolExpression
}
func (s *stringInterfaceImpl) REGEXP_LIKE(pattern StringExpression, caseSensitive ...bool) BoolExpression {
return newBinaryBoolOperatorExpression(s.root, pattern, StringRegexpLikeOperator, Bool(len(caseSensitive) > 0 && caseSensitive[0]))
return BoolExp(newExpression(&regexpLikeSerializer{
str: s.root,
pattern: pattern,
caseSensitive: len(caseSensitive) > 0 && caseSensitive[0],
}))
}
func (s *stringInterfaceImpl) NOT_REGEXP_LIKE(pattern StringExpression, caseSensitive ...bool) BoolExpression {
return newBinaryBoolOperatorExpression(s.root, pattern, StringNotRegexpLikeOperator, Bool(len(caseSensitive) > 0 && caseSensitive[0]))
return BoolExp(newExpression(&regexpLikeSerializer{
not: true,
str: s.root,
pattern: pattern,
caseSensitive: len(caseSensitive) > 0 && caseSensitive[0],
}))
}
type regexpLikeSerializer struct {
not bool
str StringExpression
pattern StringExpression
caseSensitive bool
}
func (r *regexpLikeSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
optionalWrap(out, options, func(out *SQLBuilder, options []SerializeOption) {
out.Dialect.RegexpLike(r.str, r.not, r.pattern, r.caseSensitive)(statement, out, options...)
})
}
// ---------------------------------------------------//

View file

@ -160,7 +160,7 @@ func ToSerializerValue(value interface{}) Serializer {
return clause
}
return literal(value)
return Literal(value)
}
// UnwindRowFromModel func
@ -189,7 +189,7 @@ func UnwindRowFromModel(columns []Column, data interface{}) []Serializer {
field = reflect.Indirect(structField).Interface()
}
row[i] = literal(field)
row[i] = Literal(field)
}
return row
@ -293,7 +293,7 @@ func joinAlias(tableAlias, columnAlias string) string {
return strings.TrimRight(tableAlias, ".*") + "." + columnAlias
}
func optional[T any](value []T) T {
func singleOptional[T any](value []T) T {
if len(value) > 0 {
return value[0]
}