Allow Raw helper to accept named arguments
This commit is contained in:
parent
9385f462df
commit
7af9072b8d
12 changed files with 340 additions and 36 deletions
|
|
@ -2,6 +2,8 @@ package jet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -394,22 +396,148 @@ func WRAP(expression ...Expression) Expression {
|
||||||
type rawExpression struct {
|
type rawExpression struct {
|
||||||
ExpressionInterfaceImpl
|
ExpressionInterfaceImpl
|
||||||
|
|
||||||
Raw string
|
Raw string
|
||||||
|
NamedArgument map[string]interface{}
|
||||||
|
noWrap bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||||
out.WriteString(n.Raw)
|
raw := n.Raw
|
||||||
|
|
||||||
|
type namedArgumentPosition struct {
|
||||||
|
Name string
|
||||||
|
Value interface{}
|
||||||
|
Position int
|
||||||
|
}
|
||||||
|
|
||||||
|
var namedArgumentPositions []namedArgumentPosition
|
||||||
|
|
||||||
|
for namedArg, value := range n.NamedArgument {
|
||||||
|
rawCopy := n.Raw
|
||||||
|
rawIndex := 0
|
||||||
|
exists := false
|
||||||
|
|
||||||
|
// one named argument can occur multiple times inside raw string
|
||||||
|
for {
|
||||||
|
index := strings.Index(rawCopy, namedArg)
|
||||||
|
if index == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
exists = true
|
||||||
|
namedArgumentPositions = append(namedArgumentPositions, namedArgumentPosition{
|
||||||
|
Name: namedArg,
|
||||||
|
Value: value,
|
||||||
|
Position: rawIndex + index,
|
||||||
|
})
|
||||||
|
|
||||||
|
rawCopy = rawCopy[index+len(namedArg):]
|
||||||
|
rawIndex += index + len(namedArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
panic("jet: named argument '" + namedArg + "' does not appear in raw query")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(namedArgumentPositions, func(i, j int) bool {
|
||||||
|
return namedArgumentPositions[i].Position < namedArgumentPositions[j].Position
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, namedArgumentPos := range namedArgumentPositions {
|
||||||
|
// if named argument does not exists in raw string do not add argument to the list of arguments
|
||||||
|
// It can happen if the same argument occurs multiple times in postgres query.
|
||||||
|
if !strings.Contains(raw, namedArgumentPos.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out.Args = append(out.Args, namedArgumentPos.Value)
|
||||||
|
currentArgNum := len(out.Args)
|
||||||
|
|
||||||
|
dialectPlaceholder := out.Dialect.ArgumentPlaceholder()(currentArgNum)
|
||||||
|
// if placeholder is not unique identifier ($1, $2, etc..), we will replace just one occurence of the argument
|
||||||
|
toReplace := -1 // all occurrences
|
||||||
|
if dialectPlaceholder == "?" {
|
||||||
|
toReplace = 1 // just one occurrence
|
||||||
|
}
|
||||||
|
raw = strings.Replace(raw, namedArgumentPos.Name, dialectPlaceholder, toReplace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !n.noWrap && !contains(options, NoWrap) {
|
||||||
|
raw = "(" + raw + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw can be used for any unsupported functions, operators or expressions.
|
// Raw can be used for any unsupported functions, operators or expressions.
|
||||||
// For example: Raw("current_database()")
|
// For example: Raw("current_database()")
|
||||||
func Raw(raw string, parent ...Expression) Expression {
|
func Raw(raw string, namedArgs ...map[string]interface{}) Expression {
|
||||||
rawExp := &rawExpression{Raw: raw}
|
var namedArguments map[string]interface{}
|
||||||
|
|
||||||
|
if len(namedArgs) > 0 {
|
||||||
|
namedArguments = namedArgs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
rawExp := &rawExpression{
|
||||||
|
Raw: raw,
|
||||||
|
NamedArgument: namedArguments,
|
||||||
|
}
|
||||||
|
rawExp.ExpressionInterfaceImpl.Parent = rawExp
|
||||||
|
|
||||||
|
return rawExp
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawWithParent is a Raw constructor used for construction dialect specific expression
|
||||||
|
func RawWithParent(raw string, parent ...Expression) Expression {
|
||||||
|
rawExp := &rawExpression{
|
||||||
|
Raw: raw,
|
||||||
|
noWrap: true,
|
||||||
|
}
|
||||||
rawExp.ExpressionInterfaceImpl.Parent = OptionalOrDefaultExpression(rawExp, parent...)
|
rawExp.ExpressionInterfaceImpl.Parent = OptionalOrDefaultExpression(rawExp, parent...)
|
||||||
|
|
||||||
return rawExp
|
return rawExp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Raw helper that for integer expressions
|
||||||
|
func RawInt(raw string, namedArgs ...map[string]interface{}) IntegerExpression {
|
||||||
|
return IntExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for float expressions
|
||||||
|
func RawFloat(raw string, namedArgs ...map[string]interface{}) FloatExpression {
|
||||||
|
return FloatExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for string expressions
|
||||||
|
func RawString(raw string, namedArgs ...map[string]interface{}) StringExpression {
|
||||||
|
return StringExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for time expressions
|
||||||
|
func RawTime(raw string, namedArgs ...map[string]interface{}) TimeExpression {
|
||||||
|
return TimeExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for time with time zone expressions
|
||||||
|
func RawTimez(raw string, namedArgs ...map[string]interface{}) TimezExpression {
|
||||||
|
return TimezExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for timestamp expressions
|
||||||
|
func RawTimestamp(raw string, namedArgs ...map[string]interface{}) TimestampExpression {
|
||||||
|
return TimestampExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for timestamp with time zone expressions
|
||||||
|
func RawTimestampz(raw string, namedArgs ...map[string]interface{}) TimestampzExpression {
|
||||||
|
return TimestampzExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper that for date expressions
|
||||||
|
func RawDate(raw string, namedArgs ...map[string]interface{}) DateExpression {
|
||||||
|
return DateExp(Raw(raw, namedArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
// UUID is a helper function to create string literal expression from uuid object
|
// UUID is a helper function to create string literal expression from uuid object
|
||||||
// value can be any uuid type with a String method
|
// value can be any uuid type with a String method
|
||||||
func UUID(value fmt.Stringer) StringExpression {
|
func UUID(value fmt.Stringer) StringExpression {
|
||||||
|
|
|
||||||
|
|
@ -226,12 +226,14 @@ func AssertFileNamesEqual(t *testing.T, fileInfos []os.FileInfo, fileNames ...st
|
||||||
func AssertDeepEqual(t *testing.T, actual, expected interface{}, msg ...string) {
|
func AssertDeepEqual(t *testing.T, actual, expected interface{}, msg ...string) {
|
||||||
if !assert.True(t, cmp.Equal(actual, expected), msg) {
|
if !assert.True(t, cmp.Equal(actual, expected), msg) {
|
||||||
printDiff(actual, expected)
|
printDiff(actual, expected)
|
||||||
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertQueryString(t *testing.T, actual, expected string) {
|
func assertQueryString(t *testing.T, actual, expected string) {
|
||||||
if !assert.Equal(t, actual, expected) {
|
if !assert.Equal(t, actual, expected) {
|
||||||
printDiff(actual, expected)
|
printDiff(actual, expected)
|
||||||
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,9 +70,22 @@ 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
|
||||||
|
|
||||||
// Raw can be used for any unsupported functions, operators or expressions.
|
// RawArgs is type used to pass optional arguments to Raw method
|
||||||
// For example: Raw("current_database()")
|
type RawArgs = map[string]interface{}
|
||||||
var Raw = jet.Raw
|
|
||||||
|
var (
|
||||||
|
// Raw can be used for any unsupported functions, operators or expressions.
|
||||||
|
// For example: Raw("current_database()")
|
||||||
|
Raw = jet.Raw
|
||||||
|
|
||||||
|
// Raw helper methods for each of the mysql type
|
||||||
|
RawInt = jet.RawInt
|
||||||
|
RawFloat = jet.RawFloat
|
||||||
|
RawString = jet.RawString
|
||||||
|
RawTime = jet.RawTime
|
||||||
|
RawTimestamp = jet.RawTimestamp
|
||||||
|
RawDate = jet.RawDate
|
||||||
|
)
|
||||||
|
|
||||||
// Func can be used to call an custom or as of yet unsupported function in the database.
|
// Func can be used to call an custom or as of yet unsupported function in the database.
|
||||||
var Func = jet.Func
|
var Func = jet.Func
|
||||||
|
|
|
||||||
56
mysql/expressions_test.go
Normal file
56
mysql/expressions_test.go
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
time2 "time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRaw(t *testing.T) {
|
||||||
|
assertSerialize(t, Raw("current_database()"), "(current_database())")
|
||||||
|
|
||||||
|
assertSerialize(t, Raw(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22}),
|
||||||
|
"(? + table.colInt + ?)", 11, 22)
|
||||||
|
|
||||||
|
assertSerialize(t,
|
||||||
|
Int(700).ADD(RawInt("#1 + table.colInt + #2", RawArgs{"#1": 11, "#2": 22})),
|
||||||
|
"(? + (? + table.colInt + ?))",
|
||||||
|
int64(700), 11, 22)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawDuplicateArguments(t *testing.T) {
|
||||||
|
assertSerialize(t, Raw(":arg + table.colInt + :arg", RawArgs{":arg": 11}),
|
||||||
|
"(? + table.colInt + ?)", 11, 11)
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("#age + table.colInt + #year + #age + #year + 11", RawArgs{"#age": 11, "#year": 2000}),
|
||||||
|
"(? + table.colInt + ? + ? + ? + 11)", 11, 2000, 11, 2000)
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("#1 + all_types.integer + #2 + #1 + #2 + #3 + #4",
|
||||||
|
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}),
|
||||||
|
`(? + all_types.integer + ? + ? + ? + ? + ?)`, 11, 22, 11, 22, 33, 44)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawInvalidArguments(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
require.Equal(t, "jet: named argument 'first_arg' does not appear in raw query", r)
|
||||||
|
}()
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("table.colInt + :second_arg", RawArgs{"first_arg": 11}), "(table.colInt + ?)", 22)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawType(t *testing.T) {
|
||||||
|
assertSerialize(t, RawFloat("table.colInt + &float", RawArgs{"&float": 11.22}).EQ(Float(3.14)),
|
||||||
|
"((table.colInt + ?) = ?)", 11.22, 3.14)
|
||||||
|
assertSerialize(t, RawString("table.colStr || str", RawArgs{"str": "doe"}).EQ(String("john doe")),
|
||||||
|
"((table.colStr || ?) = ?)", "doe", "john doe")
|
||||||
|
|
||||||
|
time := time2.Now()
|
||||||
|
assertSerialize(t, RawTime("table.colTime").EQ(TimeT(time)),
|
||||||
|
"((table.colTime) = CAST(? AS TIME))", time)
|
||||||
|
assertSerialize(t, RawTimestamp("table.colTimestamp").EQ(TimestampT(time)),
|
||||||
|
"((table.colTimestamp) = TIMESTAMP(?))", time)
|
||||||
|
assertSerialize(t, RawDate("table.colDate").EQ(DateT(time)),
|
||||||
|
"((table.colDate) = CAST(? AS DATE))", time)
|
||||||
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ func INTERVAL(value interface{}, unitType unitType) Interval {
|
||||||
// INTERVALe creates new temporal interval from expresion and unit type.
|
// INTERVALe creates new temporal interval from expresion and unit type.
|
||||||
func INTERVALe(expr Expression, unitType unitType) Interval {
|
func INTERVALe(expr Expression, unitType unitType) Interval {
|
||||||
return jet.NewInterval(jet.ListSerializer{
|
return jet.NewInterval(jet.ListSerializer{
|
||||||
Serializers: []jet.Serializer{expr, jet.Raw(string(unitType))},
|
Serializers: []jet.Serializer{expr, jet.RawWithParent(string(unitType))},
|
||||||
Separator: " ",
|
Separator: " ",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,15 +136,15 @@ LOCK IN SHARE MODE;
|
||||||
func TestSelect_NOT_EXISTS(t *testing.T) {
|
func TestSelect_NOT_EXISTS(t *testing.T) {
|
||||||
testutils.AssertStatementSql(t,
|
testutils.AssertStatementSql(t,
|
||||||
SELECT(table1ColInt).
|
SELECT(table1ColInt).
|
||||||
FROM(table1).
|
FROM(table1).
|
||||||
WHERE(
|
WHERE(
|
||||||
NOT(EXISTS(
|
NOT(EXISTS(
|
||||||
SELECT(table2ColInt).
|
SELECT(table2ColInt).
|
||||||
FROM(table2).
|
FROM(table2).
|
||||||
WHERE(
|
WHERE(
|
||||||
table1ColInt.EQ(table2ColInt),
|
table1ColInt.EQ(table2ColInt),
|
||||||
),
|
),
|
||||||
))), `
|
))), `
|
||||||
SELECT table1.col_int AS "table1.col_int"
|
SELECT table1.col_int AS "table1.col_int"
|
||||||
FROM db.table1
|
FROM db.table1
|
||||||
WHERE (NOT (EXISTS (
|
WHERE (NOT (EXISTS (
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,24 @@ 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
|
||||||
|
|
||||||
// Raw can be used for any unsupported functions, operators or expressions.
|
// RawArgs is type used to pass optional arguments to Raw method
|
||||||
// For example: Raw("current_database()")
|
type RawArgs = map[string]interface{}
|
||||||
var Raw = jet.Raw
|
|
||||||
|
var (
|
||||||
|
// Raw can be used for any unsupported functions, operators or expressions.
|
||||||
|
// For example: Raw("current_database()")
|
||||||
|
Raw = jet.Raw
|
||||||
|
|
||||||
|
// Raw helper methods for each of the postgres type
|
||||||
|
RawInt = jet.RawInt
|
||||||
|
RawFloat = jet.RawFloat
|
||||||
|
RawString = jet.RawString
|
||||||
|
RawTime = jet.RawTime
|
||||||
|
RawTimez = jet.RawTimez
|
||||||
|
RawTimestamp = jet.RawTimestamp
|
||||||
|
RawTimestampz = jet.RawTimestampz
|
||||||
|
RawDate = jet.RawDate
|
||||||
|
)
|
||||||
|
|
||||||
// Func can be used to call an custom or as of yet unsupported function in the database.
|
// Func can be used to call an custom or as of yet unsupported function in the database.
|
||||||
var Func = jet.Func
|
var Func = jet.Func
|
||||||
|
|
|
||||||
64
postgres/expressions_test.go
Normal file
64
postgres/expressions_test.go
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRaw(t *testing.T) {
|
||||||
|
assertSerialize(t, Raw("current_database()"), "(current_database())")
|
||||||
|
|
||||||
|
assertSerialize(t, Raw(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22}),
|
||||||
|
"($1 + table.colInt + $2)", 11, 22)
|
||||||
|
|
||||||
|
assertSerialize(t,
|
||||||
|
Int(700).ADD(RawInt(":first_arg + table.colInt + :second_arg", RawArgs{":first_arg": 11, ":second_arg": 22})),
|
||||||
|
"($1 + ($2 + table.colInt + $3))",
|
||||||
|
int64(700), 11, 22)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuplicateArguments(t *testing.T) {
|
||||||
|
|
||||||
|
assertSerialize(t, Raw(":arg + table.colInt + :arg", RawArgs{":arg": 11}),
|
||||||
|
"($1 + table.colInt + $1)", 11)
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("#age + table.colInt + #year + #age + #year + 11", RawArgs{"#age": 11, "#year": 2000}),
|
||||||
|
"($1 + table.colInt + $2 + $1 + $2 + 11)", 11, 2000)
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("#1 + all_types.integer + #2 + #1 + #2 + #3 + #4",
|
||||||
|
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}),
|
||||||
|
`($1 + all_types.integer + $2 + $1 + $2 + $3 + $4)`, 11, 22, 11, 22, 33, 44)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawInvalidArguments(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
require.Equal(t, "jet: named argument 'first_arg' does not appear in raw query", r)
|
||||||
|
}()
|
||||||
|
|
||||||
|
assertSerialize(t, Raw("table.colInt + :second_arg", RawArgs{
|
||||||
|
"first_arg": 11,
|
||||||
|
"second_arg": 22,
|
||||||
|
}), "(table.colInt + $1)", 22)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawHelperMethods(t *testing.T) {
|
||||||
|
assertSerialize(t, RawFloat("table.colInt + :float", RawArgs{":float": 11.22}).EQ(Float(3.14)),
|
||||||
|
"((table.colInt + $1) = $2)", 11.22, 3.14)
|
||||||
|
assertSerialize(t, RawString("table.colStr || str", RawArgs{"str": "doe"}).EQ(String("john doe")),
|
||||||
|
"((table.colStr || $1) = $2)", "doe", "john doe")
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
assertSerialize(t, RawTime("table.colTime").EQ(TimeT(now)),
|
||||||
|
"((table.colTime) = $1::time without time zone)", now)
|
||||||
|
assertSerialize(t, RawTimez("table.colTime").EQ(TimezT(now)),
|
||||||
|
"((table.colTime) = $1::time with time zone)", now)
|
||||||
|
assertSerialize(t, RawTimestamp("table.colTimestamp").EQ(TimestampT(now)),
|
||||||
|
"((table.colTimestamp) = $1::timestamp without time zone)", now)
|
||||||
|
assertSerialize(t, RawTimestampz("table.colTimestampz").EQ(TimestampzT(now)),
|
||||||
|
"((table.colTimestampz) = $1::timestamp with time zone)", now)
|
||||||
|
assertSerialize(t, RawDate("table.colDate").EQ(DateT(now)),
|
||||||
|
"((table.colDate) = $1::date)", now)
|
||||||
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ func INTERVAL(quantityAndUnit ...quantityAndUnit) IntervalExpression {
|
||||||
|
|
||||||
newInterval := &intervalExpression{}
|
newInterval := &intervalExpression{}
|
||||||
|
|
||||||
newInterval.Expression = jet.Raw(intervalStr, newInterval)
|
newInterval.Expression = jet.RawWithParent(intervalStr, newInterval)
|
||||||
newInterval.intervalInterfaceImpl.parent = newInterval
|
newInterval.intervalInterfaceImpl.parent = newInterval
|
||||||
|
|
||||||
return newInterval
|
return newInterval
|
||||||
|
|
|
||||||
|
|
@ -89,14 +89,17 @@ func TestExpressionOperators(t *testing.T) {
|
||||||
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
|
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
|
||||||
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
|
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
|
||||||
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
|
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
|
||||||
|
|
||||||
|
Raw("CURRENT_USER()").AS("result.raw"),
|
||||||
|
Raw(":first + COALESCE(all_types.small_int_ptr, 0) + :second", RawArgs{":first": 78, ":second": 56}).
|
||||||
|
AS("result.raw_arg"),
|
||||||
|
Raw("#1 + all_types.integer + #2 + #1 + #3 + #4", RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}).
|
||||||
|
AS("result.raw_arg2"),
|
||||||
|
|
||||||
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
|
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
|
||||||
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"),
|
||||||
|
|
||||||
Raw("DATABASE()"),
|
|
||||||
).LIMIT(2)
|
).LIMIT(2)
|
||||||
|
|
||||||
//fmt.Println(query.Sql())
|
|
||||||
|
|
||||||
testutils.AssertStatementSql(t, query, strings.Replace(`
|
testutils.AssertStatementSql(t, query, strings.Replace(`
|
||||||
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",
|
||||||
|
|
@ -105,15 +108,17 @@ SELECT all_types.'integer' IS NULL AS "result.is_null",
|
||||||
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",
|
||||||
|
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
||||||
|
(? + 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"
|
||||||
DATABASE()
|
|
||||||
FROM test_sample.all_types
|
FROM test_sample.all_types
|
||||||
LIMIT ?;
|
LIMIT ?;
|
||||||
`, "'", "`", -1), int64(11), int64(22), int64(11), int64(22), int64(2))
|
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
||||||
|
|
||||||
var dest []struct {
|
var dest []struct {
|
||||||
common.ExpressionTestResult `alias:"result.*"`
|
common.ExpressionTestResult `alias:"result.*"`
|
||||||
|
|
@ -132,6 +137,9 @@ LIMIT ?;
|
||||||
"IsNotNull": true,
|
"IsNotNull": true,
|
||||||
"In": false,
|
"In": false,
|
||||||
"InSelect": false,
|
"InSelect": false,
|
||||||
|
"Raw": "jet@localhost",
|
||||||
|
"RawArg": 148,
|
||||||
|
"RawArg2": -1479,
|
||||||
"NotIn": null,
|
"NotIn": null,
|
||||||
"NotInSelect": true
|
"NotInSelect": true
|
||||||
},
|
},
|
||||||
|
|
@ -140,6 +148,9 @@ LIMIT ?;
|
||||||
"IsNotNull": false,
|
"IsNotNull": false,
|
||||||
"In": null,
|
"In": null,
|
||||||
"InSelect": null,
|
"InSelect": null,
|
||||||
|
"Raw": "jet@localhost",
|
||||||
|
"RawArg": 134,
|
||||||
|
"RawArg2": -1479,
|
||||||
"NotIn": null,
|
"NotIn": null,
|
||||||
"NotInSelect": null
|
"NotInSelect": null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/go-jet/jet/v2/internal/testutils"
|
"github.com/go-jet/jet/v2/internal/testutils"
|
||||||
. "github.com/go-jet/jet/v2/postgres"
|
. "github.com/go-jet/jet/v2/postgres"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
|
||||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/view"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/view"
|
||||||
"github.com/go-jet/jet/v2/tests/testdata/results/common"
|
"github.com/go-jet/jet/v2/tests/testdata/results/common"
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAllTypesSelect(t *testing.T) {
|
func TestAllTypesSelect(t *testing.T) {
|
||||||
|
|
@ -221,12 +223,16 @@ func TestExpressionOperators(t *testing.T) {
|
||||||
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
|
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
|
||||||
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
|
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
|
||||||
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
|
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
|
||||||
|
|
||||||
|
Raw("CURRENT_USER").AS("result.raw"),
|
||||||
|
Raw("#1 + COALESCE(all_types.small_int_ptr, 0) + #2", RawArgs{"#1": 78, "#2": 56}).AS("result.raw_arg"),
|
||||||
|
Raw("#1 + all_types.integer + #2 + #1 + #3 + #4",
|
||||||
|
RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}).AS("result.raw_arg2"),
|
||||||
|
|
||||||
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
|
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
|
||||||
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())
|
|
||||||
|
|
||||||
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",
|
||||||
|
|
@ -235,14 +241,17 @@ SELECT all_types.integer IS NULL AS "result.is_null",
|
||||||
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",
|
||||||
(all_types.small_int_ptr NOT IN ($3, $4, NULL)) AS "result.not_in",
|
(CURRENT_USER) AS "result.raw",
|
||||||
|
($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",
|
||||||
|
(all_types.small_int_ptr NOT IN ($9, $10, 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 $5;
|
LIMIT $11;
|
||||||
`, int64(11), int64(22), int64(11), int64(22), int64(2))
|
`, int64(11), int64(22), 78, 56, 11, 22, 33, 44, int64(11), int64(22), int64(2))
|
||||||
|
|
||||||
var dest []struct {
|
var dest []struct {
|
||||||
common.ExpressionTestResult `alias:"result.*"`
|
common.ExpressionTestResult `alias:"result.*"`
|
||||||
|
|
@ -261,6 +270,9 @@ LIMIT $5;
|
||||||
"IsNotNull": true,
|
"IsNotNull": true,
|
||||||
"In": false,
|
"In": false,
|
||||||
"InSelect": false,
|
"InSelect": false,
|
||||||
|
"Raw": "jet",
|
||||||
|
"RawArg": 148,
|
||||||
|
"RawArg2": 421,
|
||||||
"NotIn": null,
|
"NotIn": null,
|
||||||
"NotInSelect": true
|
"NotInSelect": true
|
||||||
},
|
},
|
||||||
|
|
@ -269,6 +281,9 @@ LIMIT $5;
|
||||||
"IsNotNull": false,
|
"IsNotNull": false,
|
||||||
"In": null,
|
"In": null,
|
||||||
"InSelect": null,
|
"InSelect": null,
|
||||||
|
"Raw": "jet",
|
||||||
|
"RawArg": 134,
|
||||||
|
"RawArg2": 421,
|
||||||
"NotIn": null,
|
"NotIn": null,
|
||||||
"NotInSelect": null
|
"NotInSelect": null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1c977643ceb0df149fc953ad617e2a86c6ecdd65
|
Subproject commit 0d52780c6510d4b1e560081a82648b85c555ce43
|
||||||
Loading…
Add table
Add a link
Reference in a new issue