Expression casting between builtin types.

This commit is contained in:
zer0sub 2019-06-02 18:12:44 +02:00
parent fcd3596780
commit 37a55e6ee3
8 changed files with 294 additions and 47 deletions

154
sqlbuilder/cast.go Normal file
View file

@ -0,0 +1,154 @@
package sqlbuilder
type cast struct {
expression expression
castType string
}
func newCast(expression expression, castType string) cast {
return cast{
expression: expression,
castType: castType,
}
}
func (b *cast) serialize(statement statementType, out *queryData, options ...serializeOption) error {
err := b.expression.serialize(statement, out, options...)
out.writeString("::" + b.castType)
return err
}
type boolCast struct {
expressionInterfaceImpl
boolInterfaceImpl
cast
}
func newBoolCast(expression expression) BoolExpression {
boolCast := &boolCast{cast: newCast(expression, "boolean")}
boolCast.boolInterfaceImpl.parent = boolCast
boolCast.expressionInterfaceImpl.parent = boolCast
return boolCast
}
type integerCast struct {
expressionInterfaceImpl
integerInterfaceImpl
cast
}
func newIntegerCast(expression expression) IntegerExpression {
integerCast := &integerCast{cast: newCast(expression, "integer")}
integerCast.integerInterfaceImpl.parent = integerCast
integerCast.expressionInterfaceImpl.parent = integerCast
return integerCast
}
type floatCast struct {
expressionInterfaceImpl
floatInterfaceImpl
cast
}
func newDoubleCast(expression expression) FloatExpression {
floatCast := &floatCast{cast: newCast(expression, "double precision")}
floatCast.floatInterfaceImpl.parent = floatCast
floatCast.expressionInterfaceImpl.parent = floatCast
return floatCast
}
type textCast struct {
expressionInterfaceImpl
stringInterfaceImpl
cast
}
func newTextCast(expression expression) StringExpression {
textCast := &textCast{cast: newCast(expression, "text")}
textCast.stringInterfaceImpl.parent = textCast
textCast.expressionInterfaceImpl.parent = textCast
return textCast
}
type dateCast struct {
expressionInterfaceImpl
dateInterfaceImpl
cast
}
func newDateCast(expression expression) DateExpression {
dateCast := &dateCast{cast: newCast(expression, "date")}
dateCast.dateInterfaceImpl.parent = dateCast
dateCast.expressionInterfaceImpl.parent = dateCast
return dateCast
}
type timeCast struct {
expressionInterfaceImpl
timeInterfaceImpl
cast
}
func newTimeCast(expression expression) TimeExpression {
timeCast := &timeCast{cast: newCast(expression, "time without time zone")}
timeCast.timeInterfaceImpl.parent = timeCast
timeCast.expressionInterfaceImpl.parent = timeCast
return timeCast
}
type timezCast struct {
expressionInterfaceImpl
timezInterfaceImpl
cast
}
func newTimezCast(expression expression) TimezExpression {
timezCast := &timezCast{cast: newCast(expression, "time with time zone")}
timezCast.timezInterfaceImpl.parent = timezCast
timezCast.expressionInterfaceImpl.parent = timezCast
return timezCast
}
type timestampCast struct {
expressionInterfaceImpl
timestampInterfaceImpl
cast
}
func newTimestampCast(expression expression) TimestampExpression {
timestampCast := &timestampCast{cast: newCast(expression, "timestamp without time zone")}
timestampCast.timestampInterfaceImpl.parent = timestampCast
timestampCast.expressionInterfaceImpl.parent = timestampCast
return timestampCast
}
type timestampzCast struct {
expressionInterfaceImpl
timestampzInterfaceImpl
cast
}
func newTimestampzCast(expression expression) TimestampzExpression {
timestampzCast := &timestampzCast{cast: newCast(expression, "timestamp with time zone")}
timestampzCast.timestampzInterfaceImpl.parent = timestampzCast
timestampzCast.expressionInterfaceImpl.parent = timestampzCast
return timestampzCast
}

View file

@ -139,11 +139,11 @@ func (q *queryData) write(data []byte) {
}
func isPreSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n'
return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':'
}
func isPostSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n'
return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':'
}
func (q *queryData) writeString(str string) {

View file

@ -21,6 +21,16 @@ type expression interface {
ASC() orderByClause
DESC() orderByClause
CAST_TO_BOOL() BoolExpression
CAST_TO_INTEGER() IntegerExpression
CAST_TO_DOUBLE() FloatExpression
CAST_TO_TEXT() StringExpression
CAST_TO_DATE() DateExpression
CAST_TO_TIME() TimeExpression
CAST_TO_TIMEZ() TimezExpression
CAST_TO_TIMESTAMP() TimestampExpression
CAST_TO_TIMESTAMPZ() TimestampzExpression
}
type expressionInterfaceImpl struct {
@ -55,6 +65,42 @@ func (e *expressionInterfaceImpl) DESC() orderByClause {
return &orderByClauseImpl{expression: e.parent, ascent: false}
}
func (e *expressionInterfaceImpl) CAST_TO_BOOL() BoolExpression {
return newBoolCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_INTEGER() IntegerExpression {
return newIntegerCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_DOUBLE() FloatExpression {
return newDoubleCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_TEXT() StringExpression {
return newTextCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_DATE() DateExpression {
return newDateCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_TIME() TimeExpression {
return newTimeCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_TIMEZ() TimezExpression {
return newTimezCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_TIMESTAMP() TimestampExpression {
return newTimestampCast(e.parent)
}
func (e *expressionInterfaceImpl) CAST_TO_TIMESTAMPZ() TimestampzExpression {
return newTimestampzCast(e.parent)
}
func (e *expressionInterfaceImpl) serializeForGroupBy(statement statementType, out *queryData) error {
return e.parent.serialize(statement, out, NO_WRAP)
}

View file

@ -23,3 +23,40 @@ func TestExpressionIS_NOT_DISTINCT_FROM(t *testing.T) {
assertExpressionSerialize(t, table2Col3.IS_NOT_DISTINCT_FROM(table2Col4), "(table2.col3 IS NOT DISTINCT FROM table2.col4)")
assertExpressionSerialize(t, table2Col3.ADD(table2Col3).IS_NOT_DISTINCT_FROM(Int(23)), "((table2.col3 + table2.col3) IS NOT DISTINCT FROM $1)", int64(23))
}
func TestExpressionCAST_TO_BOOL(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_BOOL(), "table2.col3::boolean")
assertExpressionSerialize(t, table2Col3.ADD(table2Col3).CAST_TO_BOOL(), "(table2.col3 + table2.col3)::boolean")
}
func TestExpressionCAST_TO_INTEGER(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_INTEGER(), "table2.col3::integer")
}
func TestExpressionCAST_TO_DOUBLE(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_DOUBLE(), "table2.col3::double precision")
}
func TestExpressionCAST_TO_TEXT(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_TEXT(), "table2.col3::text")
}
func TestExpressionCAST_TO_DATE(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_DATE(), "table2.col3::date")
}
func TestExpressionCAST_TO_TIME(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_TIME(), "table2.col3::time without time zone")
}
func TestExpressionCAST_TO_TIMEZ(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_TIMEZ(), "table2.col3::time with time zone")
}
func TestExpressionCAST_TO_TIMESTAMP(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_TIMESTAMP(), "table2.col3::timestamp without time zone")
}
func TestExpressionCAST_TO_TIMESTAMPZ(t *testing.T) {
assertExpressionSerialize(t, table2Col3.CAST_TO_TIMESTAMPZ(), "table2.col3::timestamp with time zone")
}

View file

@ -88,14 +88,14 @@ type timeLiteral struct {
literalExpression
}
func Time(hour, minute, second, milliseconds int) timeExpression {
func Time(hour, minute, second, milliseconds int) TimeExpression {
timeLiteral := timeLiteral{}
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d", hour, minute, second, milliseconds)
timeLiteral.literalExpression = *Literal(timeStr)
timeLiteral.timeInterfaceImpl.parent = &timeLiteral
return &timeLiteral
return timeLiteral.CAST_TO_TIME()
}
//---------------------------------------------------//
@ -104,14 +104,14 @@ type timezLiteral struct {
literalExpression
}
func Timez(hour, minute, second, milliseconds, timezone int) timezExpression {
func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression {
timezLiteral := timezLiteral{}
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d %+03d", hour, minute, second, milliseconds, timezone)
timezLiteral.literalExpression = *Literal(timeStr)
timezLiteral.timezInterfaceImpl.parent = &timezLiteral
return &timezLiteral
return timezLiteral.CAST_TO_TIMEZ()
}
//---------------------------------------------------//
@ -127,7 +127,7 @@ func Timestamp(year, month, day, hour, minute, second, milliseconds int) Timesta
timestampLiteral.timestampInterfaceImpl.parent = &timestampLiteral
return &timestampLiteral
return timestampLiteral.CAST_TO_TIMESTAMP()
}
//---------------------------------------------------//
@ -145,7 +145,7 @@ func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone i
timestampzLiteral.timestampzInterfaceImpl.parent = &timestampzLiteral
return &timestampzLiteral
return timestampzLiteral.CAST_TO_TIMESTAMPZ()
}
//---------------------------------------------------//
@ -161,5 +161,5 @@ func Date(year, month, day int) DateExpression {
dateLiteral.literalExpression = *Literal(timeStr)
dateLiteral.dateInterfaceImpl.parent = &dateLiteral
return &dateLiteral
return dateLiteral.CAST_TO_DATE()
}

View file

@ -1,52 +1,52 @@
package sqlbuilder
type timeExpression interface {
type TimeExpression interface {
expression
EQ(rhs timeExpression) BoolExpression
NOT_EQ(rhs timeExpression) BoolExpression
IS_DISTINCT_FROM(rhs timeExpression) BoolExpression
IS_NOT_DISTINCT_FROM(rhs timeExpression) BoolExpression
EQ(rhs TimeExpression) BoolExpression
NOT_EQ(rhs TimeExpression) BoolExpression
IS_DISTINCT_FROM(rhs TimeExpression) BoolExpression
IS_NOT_DISTINCT_FROM(rhs TimeExpression) BoolExpression
LT(rhs timeExpression) BoolExpression
LT_EQ(rhs timeExpression) BoolExpression
GT(rhs timeExpression) BoolExpression
GT_EQ(rhs timeExpression) BoolExpression
LT(rhs TimeExpression) BoolExpression
LT_EQ(rhs TimeExpression) BoolExpression
GT(rhs TimeExpression) BoolExpression
GT_EQ(rhs TimeExpression) BoolExpression
}
type timeInterfaceImpl struct {
parent timeExpression
parent TimeExpression
}
func (t *timeInterfaceImpl) EQ(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) EQ(rhs TimeExpression) BoolExpression {
return EQ(t.parent, rhs)
}
func (t *timeInterfaceImpl) NOT_EQ(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) NOT_EQ(rhs TimeExpression) BoolExpression {
return NOT_EQ(t.parent, rhs)
}
func (t *timeInterfaceImpl) IS_DISTINCT_FROM(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) IS_DISTINCT_FROM(rhs TimeExpression) BoolExpression {
return IS_DISTINCT_FROM(t.parent, rhs)
}
func (t *timeInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs TimeExpression) BoolExpression {
return IS_NOT_DISTINCT_FROM(t.parent, rhs)
}
func (t *timeInterfaceImpl) LT(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) LT(rhs TimeExpression) BoolExpression {
return LT(t.parent, rhs)
}
func (t *timeInterfaceImpl) LT_EQ(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) LT_EQ(rhs TimeExpression) BoolExpression {
return LT_EQ(t.parent, rhs)
}
func (t *timeInterfaceImpl) GT(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) GT(rhs TimeExpression) BoolExpression {
return GT(t.parent, rhs)
}
func (t *timeInterfaceImpl) GT_EQ(rhs timeExpression) BoolExpression {
func (t *timeInterfaceImpl) GT_EQ(rhs TimeExpression) BoolExpression {
return GT_EQ(t.parent, rhs)
}
@ -58,7 +58,7 @@ type prefixTimeExpression struct {
prefixOpExpression
}
func newPrefixTimeExpression(operator string, expression expression) timeExpression {
func newPrefixTimeExpression(operator string, expression expression) TimeExpression {
timeExpr := prefixTimeExpression{}
timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)

View file

@ -1,52 +1,52 @@
package sqlbuilder
type timezExpression interface {
type TimezExpression interface {
expression
EQ(rhs timezExpression) BoolExpression
NOT_EQ(rhs timezExpression) BoolExpression
IS_DISTINCT_FROM(rhs timezExpression) BoolExpression
IS_NOT_DISTINCT_FROM(rhs timezExpression) BoolExpression
EQ(rhs TimezExpression) BoolExpression
NOT_EQ(rhs TimezExpression) BoolExpression
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
LT(rhs timezExpression) BoolExpression
LT_EQ(rhs timezExpression) BoolExpression
GT(rhs timezExpression) BoolExpression
GT_EQ(rhs timezExpression) BoolExpression
LT(rhs TimezExpression) BoolExpression
LT_EQ(rhs TimezExpression) BoolExpression
GT(rhs TimezExpression) BoolExpression
GT_EQ(rhs TimezExpression) BoolExpression
}
type timezInterfaceImpl struct {
parent timezExpression
parent TimezExpression
}
func (t *timezInterfaceImpl) EQ(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) EQ(rhs TimezExpression) BoolExpression {
return EQ(t.parent, rhs)
}
func (t *timezInterfaceImpl) NOT_EQ(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) NOT_EQ(rhs TimezExpression) BoolExpression {
return NOT_EQ(t.parent, rhs)
}
func (t *timezInterfaceImpl) IS_DISTINCT_FROM(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression {
return IS_DISTINCT_FROM(t.parent, rhs)
}
func (t *timezInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression {
return IS_NOT_DISTINCT_FROM(t.parent, rhs)
}
func (t *timezInterfaceImpl) LT(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) LT(rhs TimezExpression) BoolExpression {
return LT(t.parent, rhs)
}
func (t *timezInterfaceImpl) LT_EQ(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) LT_EQ(rhs TimezExpression) BoolExpression {
return LT_EQ(t.parent, rhs)
}
func (t *timezInterfaceImpl) GT(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) GT(rhs TimezExpression) BoolExpression {
return GT(t.parent, rhs)
}
func (t *timezInterfaceImpl) GT_EQ(rhs timezExpression) BoolExpression {
func (t *timezInterfaceImpl) GT_EQ(rhs TimezExpression) BoolExpression {
return GT_EQ(t.parent, rhs)
}
@ -58,7 +58,7 @@ type prefixTimezExpression struct {
prefixOpExpression
}
func newPrefixTimezExpression(operator string, expression expression) timezExpression {
func newPrefixTimezExpression(operator string, expression expression) TimezExpression {
timeExpr := prefixTimezExpression{}
timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)

View file

@ -30,6 +30,16 @@ func TestExpressionOperators(t *testing.T) {
AllTypes.Integer.IS_NULL(),
AllTypes.Timestamp.IS_NOT_NULL(),
String("TRUE").CAST_TO_BOOL(),
String("111").CAST_TO_INTEGER(),
String("11.23").CAST_TO_DOUBLE(),
Int(234).CAST_TO_TEXT(),
String("1/8/1999").CAST_TO_DATE(),
String("04:05:06.789").CAST_TO_TIME(),
String("04:05:06 PST").CAST_TO_TIMEZ(),
String("1999-01-08 04:05:06").CAST_TO_TIMESTAMP(),
String("January 8 04:05:06 1999 PST").CAST_TO_TIMESTAMPZ(),
TO_CHAR(AllTypes.Timestamp, String("HH12:MI:SS")),
TO_CHAR(AllTypes.Integer, String("999")),
TO_CHAR(AllTypes.DoublePrecision, String("999D9")),