Add support for Row expression.
This commit is contained in:
parent
58a386a3dd
commit
3fcbbec427
16 changed files with 254 additions and 63 deletions
|
|
@ -12,11 +12,6 @@ func OR(expressions ...BoolExpression) BoolExpression {
|
||||||
return newBoolExpressionListOperator("OR", expressions...)
|
return newBoolExpressionListOperator("OR", expressions...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ROW function is used to create a tuple value that consists of a set of expressions or column values.
|
|
||||||
func ROW(expressions ...Expression) Expression {
|
|
||||||
return NewFunc("ROW", expressions, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Mathematical functions ---------------//
|
// ------------------ Mathematical functions ---------------//
|
||||||
|
|
||||||
// ABSf calculates absolute value from float expression
|
// ABSf calculates absolute value from float expression
|
||||||
|
|
@ -711,7 +706,7 @@ func (p parametersSerializer) serialize(statement StatementType, out *SQLBuilder
|
||||||
if _, isStatement := expression.(Statement); isStatement {
|
if _, isStatement := expression.(Statement); isStatement {
|
||||||
expression.serialize(statement, out, options...)
|
expression.serialize(statement, out, options...)
|
||||||
} else {
|
} else {
|
||||||
skipWrap(expression).serialize(statement, out, options...)
|
expression.serialize(statement, out, append(options, NoWrap, Ident)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -374,32 +374,6 @@ func (n *starLiteral) serialize(statement StatementType, out *SQLBuilder, option
|
||||||
|
|
||||||
//---------------------------------------------------//
|
//---------------------------------------------------//
|
||||||
|
|
||||||
type wrap struct {
|
|
||||||
ExpressionInterfaceImpl
|
|
||||||
expressions []Expression
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *wrap) serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
||||||
out.WriteString("(")
|
|
||||||
|
|
||||||
if len(n.expressions) == 1 {
|
|
||||||
options = append(options, NoWrap, Ident)
|
|
||||||
}
|
|
||||||
serializeExpressionList(statementType, n.expressions, ", ", out, options...)
|
|
||||||
|
|
||||||
out.WriteString(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WRAP wraps list of expressions with brackets - ( expression1, expression2, ... )
|
|
||||||
func WRAP(expression ...Expression) Expression {
|
|
||||||
wrap := &wrap{expressions: expression}
|
|
||||||
wrap.ExpressionInterfaceImpl.Parent = wrap
|
|
||||||
|
|
||||||
return wrap
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------//
|
|
||||||
|
|
||||||
type rawExpression struct {
|
type rawExpression struct {
|
||||||
ExpressionInterfaceImpl
|
ExpressionInterfaceImpl
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,12 @@ type orderSetAggregateFuncExpression struct {
|
||||||
|
|
||||||
func (p *orderSetAggregateFuncExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
func (p *orderSetAggregateFuncExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||||
out.WriteString(p.name)
|
out.WriteString(p.name)
|
||||||
WRAP(p.fraction).serialize(statement, out, FallTrough(options)...)
|
|
||||||
|
if p.fraction != nil {
|
||||||
|
WRAP(p.fraction).serialize(statement, out, FallTrough(options)...)
|
||||||
|
} else {
|
||||||
|
WRAP().serialize(statement, out, FallTrough(options)...)
|
||||||
|
}
|
||||||
out.WriteString("WITHIN GROUP")
|
out.WriteString("WITHIN GROUP")
|
||||||
p.orderBy.serialize(statement, out)
|
p.orderBy.serialize(statement, out)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
78
internal/jet/row_expression.go
Normal file
78
internal/jet/row_expression.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
package jet
|
||||||
|
|
||||||
|
// RowExpression interface
|
||||||
|
type RowExpression interface {
|
||||||
|
Expression
|
||||||
|
|
||||||
|
EQ(rhs RowExpression) BoolExpression
|
||||||
|
NOT_EQ(rhs RowExpression) BoolExpression
|
||||||
|
IS_DISTINCT_FROM(rhs RowExpression) BoolExpression
|
||||||
|
IS_NOT_DISTINCT_FROM(rhs RowExpression) BoolExpression
|
||||||
|
|
||||||
|
LT(rhs RowExpression) BoolExpression
|
||||||
|
LT_EQ(rhs RowExpression) BoolExpression
|
||||||
|
GT(rhs RowExpression) BoolExpression
|
||||||
|
GT_EQ(rhs RowExpression) BoolExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
type rowInterfaceImpl struct {
|
||||||
|
parent RowExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) EQ(rhs RowExpression) BoolExpression {
|
||||||
|
return Eq(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) NOT_EQ(rhs RowExpression) BoolExpression {
|
||||||
|
return NotEq(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) IS_DISTINCT_FROM(rhs RowExpression) BoolExpression {
|
||||||
|
return IsDistinctFrom(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs RowExpression) BoolExpression {
|
||||||
|
return IsNotDistinctFrom(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) GT(rhs RowExpression) BoolExpression {
|
||||||
|
return Gt(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) GT_EQ(rhs RowExpression) BoolExpression {
|
||||||
|
return GtEq(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) LT(rhs RowExpression) BoolExpression {
|
||||||
|
return Lt(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rowInterfaceImpl) LT_EQ(rhs RowExpression) BoolExpression {
|
||||||
|
return LtEq(n.parent, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------//
|
||||||
|
|
||||||
|
type rowExpressionWrapper struct {
|
||||||
|
rowInterfaceImpl
|
||||||
|
Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// RowExp serves as a wrapper for an arbitrary expression, treating it as a row expression.
|
||||||
|
// This enables the Go compiler to interpret any expression as a row expression
|
||||||
|
// Note: This does not modify the generated SQL builder output by adding a SQL CAST operation.
|
||||||
|
func RowExp(expression Expression) RowExpression {
|
||||||
|
rowExpressionWrap := rowExpressionWrapper{Expression: expression}
|
||||||
|
rowExpressionWrap.rowInterfaceImpl.parent = &rowExpressionWrap
|
||||||
|
return &rowExpressionWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROW function is used to create a tuple value that consists of a set of expressions or column values.
|
||||||
|
func ROW(expressions ...Expression) RowExpression {
|
||||||
|
return RowExp(NewFunc("ROW", expressions, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRAP creates row expressions without ROW keyword `( expression1, expression2, ... )`.
|
||||||
|
func WRAP(expressions ...Expression) RowExpression {
|
||||||
|
return RowExp(NewFunc("", expressions, nil))
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,9 @@ type DateTimeExpression = jet.TimestampExpression
|
||||||
// TimestampExpression interface
|
// TimestampExpression interface
|
||||||
type TimestampExpression = jet.TimestampExpression
|
type TimestampExpression = jet.TimestampExpression
|
||||||
|
|
||||||
|
// RowExpression interface
|
||||||
|
type RowExpression = jet.RowExpression
|
||||||
|
|
||||||
// BoolExp is bool expression wrapper around arbitrary expression.
|
// BoolExp is bool expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as bool expression.
|
// Allows go compiler to see any expression as bool expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
@ -70,6 +73,11 @@ var DateTimeExp = jet.TimestampExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var TimestampExp = jet.TimestampExp
|
var TimestampExp = jet.TimestampExp
|
||||||
|
|
||||||
|
// RowExp serves as a wrapper for an arbitrary expression, treating it as a row expression.
|
||||||
|
// This enables the Go compiler to interpret any expression as a row expression
|
||||||
|
// Note: This does not modify the generated SQL builder output by adding a SQL CAST operation.
|
||||||
|
var RowExp = jet.RowExp
|
||||||
|
|
||||||
// CustomExpression is used to define custom expressions.
|
// CustomExpression is used to define custom expressions.
|
||||||
var CustomExpression = jet.CustomExpression
|
var CustomExpression = jet.CustomExpression
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ type TimestampExpression = jet.TimestampExpression
|
||||||
// TimestampzExpression interface
|
// TimestampzExpression interface
|
||||||
type TimestampzExpression = jet.TimestampzExpression
|
type TimestampzExpression = jet.TimestampzExpression
|
||||||
|
|
||||||
|
// RowExpression interface
|
||||||
|
type RowExpression = jet.RowExpression
|
||||||
|
|
||||||
// DateRange Expression interface
|
// DateRange Expression interface
|
||||||
type DateRange = jet.Range[DateExpression]
|
type DateRange = jet.Range[DateExpression]
|
||||||
|
|
||||||
|
|
@ -99,6 +102,11 @@ var TimestampExp = jet.TimestampExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var TimestampzExp = jet.TimestampzExp
|
var TimestampzExp = jet.TimestampzExp
|
||||||
|
|
||||||
|
// RowExp serves as a wrapper for an arbitrary expression, treating it as a row expression.
|
||||||
|
// This enables the Go compiler to interpret any expression as a row expression
|
||||||
|
// Note: This does not modify the generated SQL builder output by adding a SQL CAST operation.
|
||||||
|
var RowExp = jet.RowExp
|
||||||
|
|
||||||
// RangeExp is range expression wrapper around arbitrary expression.
|
// RangeExp is range expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as range expression.
|
// Allows go compiler to see any expression as range expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,16 @@ func Uint64(value uint64) IntegerExpression {
|
||||||
// Float creates new float literal expression
|
// Float creates new float literal expression
|
||||||
var Float = jet.Float
|
var Float = jet.Float
|
||||||
|
|
||||||
|
// Float32 is constructor for 32 bit float literals
|
||||||
|
func Float32(value float32) FloatExpression {
|
||||||
|
return CAST(jet.Literal(value)).AS_REAL()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 is constructor for 64 bit float literals
|
||||||
|
func Float64(value float64) FloatExpression {
|
||||||
|
return CAST(jet.Literal(value)).AS_DOUBLE()
|
||||||
|
}
|
||||||
|
|
||||||
// Decimal creates new float literal expression
|
// Decimal creates new float literal expression
|
||||||
var Decimal = jet.Decimal
|
var Decimal = jet.Decimal
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ type DateTimeExpression = jet.TimestampExpression
|
||||||
// TimestampExpression interface
|
// TimestampExpression interface
|
||||||
type TimestampExpression = jet.TimestampExpression
|
type TimestampExpression = jet.TimestampExpression
|
||||||
|
|
||||||
|
// RowExpression interface
|
||||||
|
type RowExpression = jet.RowExpression
|
||||||
|
|
||||||
// BoolExp is bool expression wrapper around arbitrary expression.
|
// BoolExp is bool expression wrapper around arbitrary expression.
|
||||||
// Allows go compiler to see any expression as bool expression.
|
// Allows go compiler to see any expression as bool expression.
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
|
|
@ -73,6 +76,11 @@ var DateTimeExp = jet.TimestampExp
|
||||||
// Does not add sql cast to generated sql builder output.
|
// Does not add sql cast to generated sql builder output.
|
||||||
var TimestampExp = jet.TimestampExp
|
var TimestampExp = jet.TimestampExp
|
||||||
|
|
||||||
|
// RowExp serves as a wrapper for an arbitrary expression, treating it as a row expression.
|
||||||
|
// This enables the Go compiler to interpret any expression as a row expression
|
||||||
|
// Note: This does not modify the generated SQL builder output by adding a SQL CAST operation.
|
||||||
|
var RowExp = jet.RowExp
|
||||||
|
|
||||||
// CustomExpression is used to define custom expressions.
|
// CustomExpression is used to define custom expressions.
|
||||||
var CustomExpression = jet.CustomExpression
|
var CustomExpression = jet.CustomExpression
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,8 @@ var (
|
||||||
OR = jet.OR
|
OR = jet.OR
|
||||||
)
|
)
|
||||||
|
|
||||||
// ROW is construct one table row from list of expressions.
|
// ROW is construct one row from a list of expressions.
|
||||||
func ROW(expressions ...Expression) Expression {
|
var ROW = jet.WRAP
|
||||||
return jet.NewFunc("", expressions, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Mathematical functions ---------------//
|
// ------------------ Mathematical functions ---------------//
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,18 +97,18 @@ func TestExpressionOperators(t *testing.T) {
|
||||||
SELECT all_types.'integer' IS NULL AS "result.is_null",
|
SELECT all_types.'integer' IS NULL AS "result.is_null",
|
||||||
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
||||||
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
|
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
|
||||||
(all_types.small_int_ptr IN (
|
(all_types.small_int_ptr IN ((
|
||||||
SELECT all_types.'integer' AS "all_types.integer"
|
SELECT all_types.'integer' AS "all_types.integer"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
)) AS "result.in_select",
|
))) AS "result.in_select",
|
||||||
(CURRENT_USER()) AS "result.raw",
|
(CURRENT_USER()) AS "result.raw",
|
||||||
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
||||||
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
|
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
|
||||||
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
|
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
|
||||||
(all_types.small_int_ptr NOT IN (
|
(all_types.small_int_ptr NOT IN ((
|
||||||
SELECT all_types.'integer' AS "all_types.integer"
|
SELECT all_types.'integer' AS "all_types.integer"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
)) AS "result.not_in_select"
|
))) AS "result.not_in_select"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
LIMIT ?;
|
LIMIT ?;
|
||||||
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
||||||
|
|
@ -1404,3 +1404,34 @@ VALUES ('91.23', '45.67', '12.35', '56.79', 0.2, 0.22, 0.3, 0.33, 0.4, 0.44);
|
||||||
require.Equal(t, 45.67, *result.Floats.DecimalPtr)
|
require.Equal(t, 45.67, *result.Floats.DecimalPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRowExpression(t *testing.T) {
|
||||||
|
now := time.Now()
|
||||||
|
nowAddHour := time.Now().Add(time.Hour)
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
|
||||||
|
ROW(Bool(false), DateT(now)).NOT_EQ(ROW(Bool(true), DateT(now))),
|
||||||
|
ROW(TimestampT(nowAddHour), String("txt")).IS_DISTINCT_FROM(RowExp(Raw("row(NOW(), 'png')"))),
|
||||||
|
ROW(TimestampT(now), DateTimeT(nowAddHour)).GT(ROW(TimestampT(now), DateTimeT(now))),
|
||||||
|
ROW(DateTimeT(nowAddHour), Int(1)).GT_EQ(ROW(DateTimeT(now), Int(2))),
|
||||||
|
ROW(TimestampT(now), DateTimeT(nowAddHour)).LT(ROW(TimestampT(now), DateTimeT(now))),
|
||||||
|
ROW(DateTimeT(nowAddHour), Float(1.22)).LT_EQ(ROW(DateTimeT(now), Float(2.33))),
|
||||||
|
)
|
||||||
|
|
||||||
|
//fmt.Println(stmt.Sql())
|
||||||
|
//fmt.Println(stmt.DebugSql())
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
SELECT ROW(?, CAST(? AS DATE)) = ROW(?, CAST(? AS DATE)),
|
||||||
|
ROW(?, CAST(? AS DATE)) != ROW(?, CAST(? AS DATE)),
|
||||||
|
NOT(ROW(TIMESTAMP(?), ?) <=> (row(NOW(), 'png'))),
|
||||||
|
ROW(TIMESTAMP(?), CAST(? AS DATETIME)) > ROW(TIMESTAMP(?), CAST(? AS DATETIME)),
|
||||||
|
ROW(CAST(? AS DATETIME), ?) >= ROW(CAST(? AS DATETIME), ?),
|
||||||
|
ROW(TIMESTAMP(?), CAST(? AS DATETIME)) < ROW(TIMESTAMP(?), CAST(? AS DATETIME)),
|
||||||
|
ROW(CAST(? AS DATETIME), ?) <= ROW(CAST(? AS DATETIME), ?);
|
||||||
|
`)
|
||||||
|
|
||||||
|
err := stmt.Query(db, &struct{}{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,10 +164,10 @@ WITH payments_to_delete AS (
|
||||||
WHERE payment.amount < 0.5
|
WHERE payment.amount < 0.5
|
||||||
)
|
)
|
||||||
DELETE FROM dvds.payment
|
DELETE FROM dvds.payment
|
||||||
WHERE payment.payment_id IN (
|
WHERE payment.payment_id IN ((
|
||||||
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
|
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
|
||||||
FROM payments_to_delete
|
FROM payments_to_delete
|
||||||
);
|
));
|
||||||
`, "''", "`"))
|
`, "''", "`"))
|
||||||
|
|
||||||
tx, err := db.Begin()
|
tx, err := db.Begin()
|
||||||
|
|
|
||||||
|
|
@ -347,24 +347,24 @@ func TestExpressionOperators(t *testing.T) {
|
||||||
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
|
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
|
||||||
).LIMIT(2)
|
).LIMIT(2)
|
||||||
|
|
||||||
//fmt.Println(query.Sql())
|
// fmt.Println(query.Sql())
|
||||||
|
|
||||||
testutils.AssertStatementSql(t, query, `
|
testutils.AssertStatementSql(t, query, `
|
||||||
SELECT all_types.integer IS NULL AS "result.is_null",
|
SELECT all_types.integer IS NULL AS "result.is_null",
|
||||||
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
||||||
(all_types.small_int_ptr IN ($1::smallint, $2::smallint)) AS "result.in",
|
(all_types.small_int_ptr IN ($1::smallint, $2::smallint)) AS "result.in",
|
||||||
(all_types.small_int_ptr IN (
|
(all_types.small_int_ptr IN ((
|
||||||
SELECT all_types.integer AS "all_types.integer"
|
SELECT all_types.integer AS "all_types.integer"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
)) AS "result.in_select",
|
))) AS "result.in_select",
|
||||||
(CURRENT_USER) AS "result.raw",
|
(CURRENT_USER) AS "result.raw",
|
||||||
($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg",
|
($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg",
|
||||||
($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2",
|
($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2",
|
||||||
(all_types.small_int_ptr NOT IN ($9, $10::smallint, NULL)) AS "result.not_in",
|
(all_types.small_int_ptr NOT IN ($9, $10::smallint, NULL)) AS "result.not_in",
|
||||||
(all_types.small_int_ptr NOT IN (
|
(all_types.small_int_ptr NOT IN ((
|
||||||
SELECT all_types.integer AS "all_types.integer"
|
SELECT all_types.integer AS "all_types.integer"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
)) AS "result.not_in_select"
|
))) AS "result.not_in_select"
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
LIMIT $11;
|
LIMIT $11;
|
||||||
`, int8(11), int8(22), 78, 56, 11, 22, 33, 44, int64(11), int16(22), int64(2))
|
`, int8(11), int8(22), 78, 56, 11, 22, 33, 44, int64(11), int16(22), int64(2))
|
||||||
|
|
@ -1111,6 +1111,46 @@ FROM test_sample.all_types;
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRowExpression(t *testing.T) {
|
||||||
|
now := time.Now()
|
||||||
|
nowAddHour := time.Now().Add(time.Hour)
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
ROW(Int32(1), Float32(11.22), String("john")).AS("row"),
|
||||||
|
WRAP(Int64(1), Float64(11.22), String("john")).AS("wrap"),
|
||||||
|
|
||||||
|
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
|
||||||
|
WRAP(Bool(false), DateT(now)).NOT_EQ(WRAP(Bool(true), DateT(now))),
|
||||||
|
|
||||||
|
ROW(TimeT(nowAddHour)).IS_DISTINCT_FROM(RowExp(Raw("row(NOW()::time)"))),
|
||||||
|
ROW().IS_NOT_DISTINCT_FROM(ROW()),
|
||||||
|
|
||||||
|
ROW(TimestampT(now), TimestampzT(nowAddHour)).GT(WRAP(TimestampT(now), TimestampzT(now))),
|
||||||
|
ROW(TimestampzT(nowAddHour)).GT_EQ(ROW(TimestampzT(now))),
|
||||||
|
WRAP(TimestampT(now), TimestampzT(nowAddHour)).LT(ROW(TimestampT(now), TimestampzT(now))),
|
||||||
|
ROW(TimestampzT(nowAddHour)).LT_EQ(ROW(TimestampzT(now))),
|
||||||
|
)
|
||||||
|
|
||||||
|
//fmt.Println(stmt.Sql())
|
||||||
|
//fmt.Println(stmt.DebugSql())
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
SELECT ROW($1::integer, $2::real, $3::text) AS "row",
|
||||||
|
($4::bigint, $5::double precision, $6::text) AS "wrap",
|
||||||
|
ROW($7::boolean, $8::date) = ROW($9::boolean, $10::date),
|
||||||
|
($11::boolean, $12::date) != ($13::boolean, $14::date),
|
||||||
|
ROW($15::time without time zone) IS DISTINCT FROM (row(NOW()::time)),
|
||||||
|
ROW() IS NOT DISTINCT FROM ROW(),
|
||||||
|
ROW($16::timestamp without time zone, $17::timestamp with time zone) > ($18::timestamp without time zone, $19::timestamp with time zone),
|
||||||
|
ROW($20::timestamp with time zone) >= ROW($21::timestamp with time zone),
|
||||||
|
($22::timestamp without time zone, $23::timestamp with time zone) < ROW($24::timestamp without time zone, $25::timestamp with time zone),
|
||||||
|
ROW($26::timestamp with time zone) <= ROW($27::timestamp with time zone);
|
||||||
|
`)
|
||||||
|
|
||||||
|
err := stmt.Query(db, &struct{}{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSubQueryColumnReference(t *testing.T) {
|
func TestSubQueryColumnReference(t *testing.T) {
|
||||||
type expected struct {
|
type expected struct {
|
||||||
sql string
|
sql string
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,10 @@ func TestUpdateExecContext(t *testing.T) {
|
||||||
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
testutils.AssertExecContextErr(ctx, t, updateStmt, db, "context deadline exceeded")
|
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
|
||||||
|
_, err := updateStmt.ExecContext(ctx, tx)
|
||||||
|
require.Error(t, err, "context deadline exceeded")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateFrom(t *testing.T) {
|
func TestUpdateFrom(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,10 @@ SELECT orders.ship_region AS "orders.ship_region",
|
||||||
SUM(order_details.quantity) AS "product_sales"
|
SUM(order_details.quantity) AS "product_sales"
|
||||||
FROM northwind.orders
|
FROM northwind.orders
|
||||||
INNER JOIN northwind.order_details ON (orders.order_id = order_details.order_id)
|
INNER JOIN northwind.order_details ON (orders.order_id = order_details.order_id)
|
||||||
WHERE orders.ship_region IN (
|
WHERE orders.ship_region IN ((
|
||||||
SELECT top_region."orders.ship_region" AS "orders.ship_region"
|
SELECT top_region."orders.ship_region" AS "orders.ship_region"
|
||||||
FROM top_region
|
FROM top_region
|
||||||
)
|
))
|
||||||
GROUP BY orders.ship_region, order_details.product_id
|
GROUP BY orders.ship_region, order_details.product_id
|
||||||
ORDER BY SUM(order_details.quantity) DESC;
|
ORDER BY SUM(order_details.quantity) DESC;
|
||||||
`)
|
`)
|
||||||
|
|
@ -157,19 +157,19 @@ func TestWithStatementDeleteAndInsert(t *testing.T) {
|
||||||
testutils.AssertStatementSql(t, stmt, `
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
WITH remove_discontinued_orders AS (
|
WITH remove_discontinued_orders AS (
|
||||||
DELETE FROM northwind.order_details
|
DELETE FROM northwind.order_details
|
||||||
WHERE order_details.product_id IN (
|
WHERE order_details.product_id IN ((
|
||||||
SELECT products.product_id AS "products.product_id"
|
SELECT products.product_id AS "products.product_id"
|
||||||
FROM northwind.products
|
FROM northwind.products
|
||||||
WHERE products.discontinued = $1
|
WHERE products.discontinued = $1
|
||||||
)
|
))
|
||||||
RETURNING order_details.product_id AS "order_details.product_id"
|
RETURNING order_details.product_id AS "order_details.product_id"
|
||||||
),update_discontinued_price AS (
|
),update_discontinued_price AS (
|
||||||
UPDATE northwind.products
|
UPDATE northwind.products
|
||||||
SET unit_price = $2
|
SET unit_price = $2
|
||||||
WHERE products.product_id IN (
|
WHERE products.product_id IN ((
|
||||||
SELECT remove_discontinued_orders."order_details.product_id" AS "order_details.product_id"
|
SELECT remove_discontinued_orders."order_details.product_id" AS "order_details.product_id"
|
||||||
FROM remove_discontinued_orders
|
FROM remove_discontinued_orders
|
||||||
)
|
))
|
||||||
RETURNING products.product_id AS "products.product_id",
|
RETURNING products.product_id AS "products.product_id",
|
||||||
products.product_name AS "products.product_name",
|
products.product_name AS "products.product_name",
|
||||||
products.supplier_id AS "products.supplier_id",
|
products.supplier_id AS "products.supplier_id",
|
||||||
|
|
|
||||||
|
|
@ -234,18 +234,18 @@ func TestExpressionOperators(t *testing.T) {
|
||||||
SELECT all_types.integer IS NULL AS "result.is_null",
|
SELECT all_types.integer IS NULL AS "result.is_null",
|
||||||
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
||||||
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
|
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
|
||||||
(all_types.small_int_ptr IN (
|
(all_types.small_int_ptr IN ((
|
||||||
SELECT all_types.integer AS "all_types.integer"
|
SELECT all_types.integer AS "all_types.integer"
|
||||||
FROM all_types
|
FROM all_types
|
||||||
)) AS "result.in_select",
|
))) AS "result.in_select",
|
||||||
(length(121232459)) AS "result.raw",
|
(length(121232459)) AS "result.raw",
|
||||||
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
||||||
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
|
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
|
||||||
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
|
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
|
||||||
(all_types.small_int_ptr NOT IN (
|
(all_types.small_int_ptr NOT IN ((
|
||||||
SELECT all_types.integer AS "all_types.integer"
|
SELECT all_types.integer AS "all_types.integer"
|
||||||
FROM all_types
|
FROM all_types
|
||||||
)) AS "result.not_in_select"
|
))) AS "result.not_in_select"
|
||||||
FROM all_types
|
FROM all_types
|
||||||
LIMIT ?;
|
LIMIT ?;
|
||||||
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
||||||
|
|
@ -900,3 +900,36 @@ func TestDateTimeExpressions(t *testing.T) {
|
||||||
require.Equal(t, dest.JulianDay, 2.4551543576232754e+06)
|
require.Equal(t, dest.JulianDay, 2.4551543576232754e+06)
|
||||||
require.Equal(t, dest.StrfTime, "20:34")
|
require.Equal(t, dest.StrfTime, "20:34")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRowExpression(t *testing.T) {
|
||||||
|
date := Date(2000, 9, 9)
|
||||||
|
time := Time(11, 22, 11)
|
||||||
|
dateTime := DateTime(2008, 11, 22, 10, 12, 40)
|
||||||
|
dateTime2 := DateTime(2011, 1, 2, 5, 12, 40)
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
ROW(Bool(false), date).EQ(ROW(Bool(true), date)),
|
||||||
|
ROW(Bool(false), time).NOT_EQ(ROW(Bool(true), time)),
|
||||||
|
ROW(time).IS_DISTINCT_FROM(RowExp(Raw("(time('now'))"))),
|
||||||
|
ROW(dateTime, dateTime2).GT(ROW(dateTime, dateTime2)),
|
||||||
|
ROW(dateTime2).GT_EQ(ROW(dateTime)),
|
||||||
|
ROW(dateTime, dateTime2).LT(ROW(dateTime, dateTime2)),
|
||||||
|
ROW(dateTime2).LT_EQ(ROW(dateTime2)),
|
||||||
|
)
|
||||||
|
|
||||||
|
//fmt.Println(stmt.Sql())
|
||||||
|
//fmt.Println(stmt.DebugSql())
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
SELECT (FALSE, DATE('2000-09-09')) = (TRUE, DATE('2000-09-09')),
|
||||||
|
(FALSE, TIME('11:22:11')) != (TRUE, TIME('11:22:11')),
|
||||||
|
(TIME('11:22:11')) IS NOT ((time('now'))),
|
||||||
|
(DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')) > (DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')),
|
||||||
|
(DATETIME('2011-01-02 05:12:40')) >= (DATETIME('2008-11-22 10:12:40')),
|
||||||
|
(DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')) < (DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')),
|
||||||
|
(DATETIME('2011-01-02 05:12:40')) <= (DATETIME('2011-01-02 05:12:40'));
|
||||||
|
`)
|
||||||
|
|
||||||
|
err := stmt.Query(db, &struct{}{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,10 +153,10 @@ WITH payments_to_update AS (
|
||||||
)
|
)
|
||||||
UPDATE payment
|
UPDATE payment
|
||||||
SET amount = 0
|
SET amount = 0
|
||||||
WHERE payment.payment_id IN (
|
WHERE payment.payment_id IN ((
|
||||||
SELECT payments_to_update.''payment.payment_id'' AS "payment.payment_id"
|
SELECT payments_to_update.''payment.payment_id'' AS "payment.payment_id"
|
||||||
FROM payments_to_update
|
FROM payments_to_update
|
||||||
);
|
));
|
||||||
`, "''", "`", -1))
|
`, "''", "`", -1))
|
||||||
|
|
||||||
tx := beginDBTx(t)
|
tx := beginDBTx(t)
|
||||||
|
|
@ -205,10 +205,10 @@ WITH payments_to_delete AS (
|
||||||
WHERE payment.amount < 0.5
|
WHERE payment.amount < 0.5
|
||||||
)
|
)
|
||||||
DELETE FROM payment
|
DELETE FROM payment
|
||||||
WHERE payment.payment_id IN (
|
WHERE payment.payment_id IN ((
|
||||||
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
|
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
|
||||||
FROM payments_to_delete
|
FROM payments_to_delete
|
||||||
);
|
));
|
||||||
`, "''", "`", -1))
|
`, "''", "`", -1))
|
||||||
|
|
||||||
tx := beginDBTx(t)
|
tx := beginDBTx(t)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue