Add support for additional array types.
This commit is contained in:
parent
45d4ced9b0
commit
4ee047a675
47 changed files with 1994 additions and 4277 deletions
|
|
@ -1,77 +1,77 @@
|
|||
package jet
|
||||
|
||||
// ArrayExpression interface
|
||||
type ArrayExpression[E Expression] interface {
|
||||
// Array interface
|
||||
type Array[E Expression] interface {
|
||||
Expression
|
||||
|
||||
EQ(rhs ArrayExpression[E]) BoolExpression
|
||||
NOT_EQ(rhs ArrayExpression[E]) BoolExpression
|
||||
LT(rhs ArrayExpression[E]) BoolExpression
|
||||
GT(rhs ArrayExpression[E]) BoolExpression
|
||||
LT_EQ(rhs ArrayExpression[E]) BoolExpression
|
||||
GT_EQ(rhs ArrayExpression[E]) BoolExpression
|
||||
EQ(rhs Array[E]) BoolExpression
|
||||
NOT_EQ(rhs Array[E]) BoolExpression
|
||||
LT(rhs Array[E]) BoolExpression
|
||||
GT(rhs Array[E]) BoolExpression
|
||||
LT_EQ(rhs Array[E]) BoolExpression
|
||||
GT_EQ(rhs Array[E]) BoolExpression
|
||||
|
||||
CONTAINS(rhs ArrayExpression[E]) BoolExpression
|
||||
IS_CONTAINED_BY(rhs ArrayExpression[E]) BoolExpression
|
||||
OVERLAP(rhs ArrayExpression[E]) BoolExpression
|
||||
CONCAT(rhs ArrayExpression[E]) ArrayExpression[E]
|
||||
CONCAT_ELEMENT(E) ArrayExpression[E]
|
||||
CONTAINS(rhs Array[E]) BoolExpression
|
||||
IS_CONTAINED_BY(rhs Array[E]) BoolExpression
|
||||
OVERLAP(rhs Array[E]) BoolExpression
|
||||
CONCAT(rhs Array[E]) Array[E]
|
||||
CONCAT_ELEMENT(E) Array[E]
|
||||
|
||||
AT(expression IntegerExpression) Expression
|
||||
AT(expression IntegerExpression) E
|
||||
}
|
||||
|
||||
type arrayInterfaceImpl[E Expression] struct {
|
||||
parent ArrayExpression[E]
|
||||
parent Array[E]
|
||||
}
|
||||
|
||||
type BinaryBoolOp func(Expression, Expression) BoolExpression
|
||||
|
||||
func (a arrayInterfaceImpl[E]) EQ(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) EQ(rhs Array[E]) BoolExpression {
|
||||
return Eq(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) NOT_EQ(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) NOT_EQ(rhs Array[E]) BoolExpression {
|
||||
return NotEq(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) LT(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) LT(rhs Array[E]) BoolExpression {
|
||||
return Lt(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) GT(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) GT(rhs Array[E]) BoolExpression {
|
||||
return Gt(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) LT_EQ(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) LT_EQ(rhs Array[E]) BoolExpression {
|
||||
return LtEq(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) GT_EQ(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) GT_EQ(rhs Array[E]) BoolExpression {
|
||||
return GtEq(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) CONTAINS(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) CONTAINS(rhs Array[E]) BoolExpression {
|
||||
return Contains(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) IS_CONTAINED_BY(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) IS_CONTAINED_BY(rhs Array[E]) BoolExpression {
|
||||
return IsContainedBy(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) OVERLAP(rhs ArrayExpression[E]) BoolExpression {
|
||||
func (a arrayInterfaceImpl[E]) OVERLAP(rhs Array[E]) BoolExpression {
|
||||
return Overlap(a.parent, rhs)
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) CONCAT(rhs ArrayExpression[E]) ArrayExpression[E] {
|
||||
func (a arrayInterfaceImpl[E]) CONCAT(rhs Array[E]) Array[E] {
|
||||
return ArrayExp[E](NewBinaryOperatorExpression(a.parent, rhs, "||"))
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) CONCAT_ELEMENT(rhs E) ArrayExpression[E] {
|
||||
func (a arrayInterfaceImpl[E]) CONCAT_ELEMENT(rhs E) Array[E] {
|
||||
return ArrayExp[E](NewBinaryOperatorExpression(a.parent, rhs, "||"))
|
||||
}
|
||||
|
||||
func (a arrayInterfaceImpl[E]) AT(expression IntegerExpression) Expression {
|
||||
return arraySubscriptExpr(a.parent, expression)
|
||||
func (a arrayInterfaceImpl[E]) AT(at IntegerExpression) E {
|
||||
return CastToArrayElemType[E](a.parent, CustomExpression(a.parent, Token("["), at, Token("]")))
|
||||
}
|
||||
|
||||
type arrayExpressionWrapper[E Expression] struct {
|
||||
|
|
@ -79,7 +79,7 @@ type arrayExpressionWrapper[E Expression] struct {
|
|||
Expression
|
||||
}
|
||||
|
||||
func newArrayExpressionWrap[E Expression](expression Expression) ArrayExpression[E] {
|
||||
func newArrayExpressionWrap[E Expression](expression Expression) Array[E] {
|
||||
arrayExpressionWrapper := arrayExpressionWrapper[E]{Expression: expression}
|
||||
arrayExpressionWrapper.arrayInterfaceImpl.parent = &arrayExpressionWrapper
|
||||
return &arrayExpressionWrapper
|
||||
|
|
@ -88,6 +88,49 @@ func newArrayExpressionWrap[E Expression](expression Expression) ArrayExpression
|
|||
// ArrayExp is array expression wrapper around arbitrary expression.
|
||||
// Allows go compiler to see any expression as array expression.
|
||||
// Does not add sql cast to generated sql builder output.
|
||||
func ArrayExp[E Expression](expression Expression) ArrayExpression[E] {
|
||||
func ArrayExp[E Expression](expression Expression) Array[E] {
|
||||
return newArrayExpressionWrap[E](expression)
|
||||
}
|
||||
|
||||
// CastToArrayElemType casts exp to array element type
|
||||
func CastToArrayElemType[E Expression](array Array[E], exp Expression) E {
|
||||
var i Expression
|
||||
switch array.(type) {
|
||||
case Array[BoolExpression]:
|
||||
i = BoolExp(exp)
|
||||
case Array[StringExpression]:
|
||||
i = StringExp(exp)
|
||||
case Array[IntegerExpression]:
|
||||
i = IntExp(exp)
|
||||
case Array[FloatExpression]:
|
||||
i = FloatExp(exp)
|
||||
case Array[BlobExpression]:
|
||||
i = BlobExp(exp)
|
||||
case Array[DateExpression]:
|
||||
i = DateExp(exp)
|
||||
case Array[TimestampExpression]:
|
||||
i = TimestampExp(exp)
|
||||
case Array[TimestampzExpression]:
|
||||
i = TimestampzExp(exp)
|
||||
case Array[TimeExpression]:
|
||||
i = TimeExp(exp)
|
||||
case Array[TimezExpression]:
|
||||
i = TimezExp(exp)
|
||||
case Array[IntervalExpression]:
|
||||
i = IntervalExp(exp)
|
||||
}
|
||||
|
||||
return i.(E)
|
||||
}
|
||||
|
||||
// ARRAY constructor builds an array value using list of expressions.
|
||||
func ARRAY[E Expression](elems ...E) Array[E] {
|
||||
var args = make([]Serializer, len(elems))
|
||||
for i, each := range elems {
|
||||
args[i] = each
|
||||
}
|
||||
return ArrayExp[E](CustomExpression(Token("ARRAY["), ListSerializer{
|
||||
Serializers: args,
|
||||
Separator: ",",
|
||||
}, Token("]")))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package jet
|
||||
|
||||
import (
|
||||
"github.com/lib/pq"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -11,7 +10,6 @@ func TestArrayExpressionEQ(t *testing.T) {
|
|||
|
||||
func TestArrayExpressionNOT_EQ(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.NOT_EQ(table2ColArray), "(table1.col_array_string != table2.col_array_string)")
|
||||
assertClauseSerialize(t, table1ColStringArray.NOT_EQ(StringArray([]string{"x"})), "(table1.col_array_string != $1)", pq.StringArray{"x"})
|
||||
}
|
||||
|
||||
func TestArrayExpressionLT(t *testing.T) {
|
||||
|
|
@ -32,12 +30,10 @@ func TestArrayExpressionGT_EQ(t *testing.T) {
|
|||
|
||||
func TestArrayExpressionCONTAINS(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.CONTAINS(table2ColArray), "(table1.col_array_string @> table2.col_array_string)")
|
||||
assertClauseSerialize(t, table1ColStringArray.CONTAINS(StringArray([]string{"x"})), "(table1.col_array_string @> $1)", pq.StringArray{"x"})
|
||||
}
|
||||
|
||||
func TestArrayExpressionCONTAINED_BY(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.IS_CONTAINED_BY(table2ColArray), "(table1.col_array_string <@ table2.col_array_string)")
|
||||
assertClauseSerialize(t, table1ColStringArray.IS_CONTAINED_BY(StringArray([]string{"x"})), "(table1.col_array_string <@ $1)", pq.StringArray{"x"})
|
||||
}
|
||||
|
||||
func TestArrayExpressionOVERLAP(t *testing.T) {
|
||||
|
|
@ -46,14 +42,27 @@ func TestArrayExpressionOVERLAP(t *testing.T) {
|
|||
|
||||
func TestArrayExpressionCONCAT(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.CONCAT(table2ColArray), "(table1.col_array_string || table2.col_array_string)")
|
||||
assertClauseSerialize(t, table1ColStringArray.CONCAT(StringArray([]string{"x"})), "(table1.col_array_string || $1)", pq.StringArray{"x"})
|
||||
}
|
||||
|
||||
func TestArrayExpressionCONCAT_ELEMENT(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.CONCAT_ELEMENT(StringExp(table2ColArray.AT(Int(1)))), "(table1.col_array_string || (table2.col_array_string[$1]))", int64(1))
|
||||
assertClauseSerialize(t, table1ColStringArray.CONCAT_ELEMENT(StringExp(table2ColArray.AT(Int(1)))), "(table1.col_array_string || table2.col_array_string[$1])", int64(1))
|
||||
assertClauseSerialize(t, table1ColStringArray.CONCAT_ELEMENT(String("x")), "(table1.col_array_string || $1)", "x")
|
||||
}
|
||||
|
||||
func TestArrayExpressionAT(t *testing.T) {
|
||||
assertClauseSerialize(t, table1ColStringArray.AT(Int(1)), "(table1.col_array_string[$1])", int64(1))
|
||||
assertClauseSerialize(t, table1ColStringArray.AT(Int(1)), "table1.col_array_string[$1]", int64(1))
|
||||
}
|
||||
|
||||
func TestCastToArrayElemType(t *testing.T) {
|
||||
var _ BoolExpression = CastToArrayElemType[BoolExpression](ARRAY[BoolExpression](), table1Col1)
|
||||
var _ IntegerExpression = CastToArrayElemType[IntegerExpression](ARRAY[IntegerExpression](), table1Col1)
|
||||
var _ FloatExpression = CastToArrayElemType[FloatExpression](ARRAY[FloatExpression](), table1Col1)
|
||||
var _ StringExpression = CastToArrayElemType[StringExpression](ARRAY[StringExpression](), table1Col1)
|
||||
var _ BlobExpression = CastToArrayElemType[BlobExpression](ARRAY[BlobExpression](), table1Col1)
|
||||
var _ DateExpression = CastToArrayElemType[DateExpression](ARRAY[DateExpression](), table1Col1)
|
||||
var _ TimestampExpression = CastToArrayElemType[TimestampExpression](ARRAY[TimestampExpression](), table1Col1)
|
||||
var _ TimestampzExpression = CastToArrayElemType[TimestampzExpression](ARRAY[TimestampzExpression](), table1Col1)
|
||||
var _ TimeExpression = CastToArrayElemType[TimeExpression](ARRAY[TimeExpression](), table1Col1)
|
||||
var _ TimezExpression = CastToArrayElemType[TimezExpression](ARRAY[TimezExpression](), table1Col1)
|
||||
var _ IntervalExpression = CastToArrayElemType[IntervalExpression](ARRAY[IntervalExpression](), table1Col1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,17 +134,21 @@ func IntegerColumn(name string) ColumnInteger {
|
|||
//------------------------------------------------------//
|
||||
|
||||
type ColumnArray[E Expression] interface {
|
||||
ArrayExpression[E]
|
||||
Array[E]
|
||||
Column
|
||||
|
||||
From(subQuery SelectTable) ColumnArray[E]
|
||||
SET(stringExp ArrayExpression[E]) ColumnAssigment
|
||||
SET(stringExp Array[E]) ColumnAssigment
|
||||
}
|
||||
|
||||
type arrayColumnImpl[E Expression] struct {
|
||||
arrayInterfaceImpl[E]
|
||||
|
||||
ColumnExpressionImpl
|
||||
*ColumnExpressionImpl
|
||||
}
|
||||
|
||||
func (a arrayColumnImpl[E]) fromImpl(subQuery SelectTable) Projection {
|
||||
return a.From(subQuery)
|
||||
}
|
||||
|
||||
func (a arrayColumnImpl[E]) From(subQuery SelectTable) ColumnArray[E] {
|
||||
|
|
@ -155,10 +159,10 @@ func (a arrayColumnImpl[E]) From(subQuery SelectTable) ColumnArray[E] {
|
|||
return newArrayColumn
|
||||
}
|
||||
|
||||
func (a *arrayColumnImpl[E]) SET(stringExp ArrayExpression[E]) ColumnAssigment {
|
||||
func (a *arrayColumnImpl[E]) SET(stringExp Array[E]) ColumnAssigment {
|
||||
return columnAssigmentImpl{
|
||||
column: a,
|
||||
expression: stringExp,
|
||||
column: a,
|
||||
toAssign: stringExp,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package jet
|
||||
|
||||
import (
|
||||
"github.com/lib/pq"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -12,36 +11,30 @@ var subQuery = &selectTableImpl{
|
|||
func TestNewArrayColumnString(t *testing.T) {
|
||||
stringArrayColumn := ArrayColumn[StringExpression]("colArray").From(subQuery)
|
||||
assertClauseSerialize(t, stringArrayColumn, `sub_query."colArray"`)
|
||||
assertClauseSerialize(t, stringArrayColumn.EQ(StringArray([]string{"X"})), `(sub_query."colArray" = $1)`, pq.StringArray{"X"})
|
||||
assertProjectionSerialize(t, stringArrayColumn, `sub_query."colArray" AS "colArray"`)
|
||||
|
||||
arrayColumn2 := table1ColStringArray.From(subQuery)
|
||||
assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_string"`)
|
||||
assertClauseSerialize(t, arrayColumn2.EQ(StringArray([]string{"X"})), `(sub_query."table1.col_array_string" = $1)`, pq.StringArray{"X"})
|
||||
assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_string" AS "table1.col_array_string"`)
|
||||
}
|
||||
|
||||
func TestNewArrayColumnBool(t *testing.T) {
|
||||
boolArrayColumn := ArrayColumn[BoolExpression]("colArrayBool").From(subQuery)
|
||||
assertClauseSerialize(t, boolArrayColumn, `sub_query."colArrayBool"`)
|
||||
assertClauseSerialize(t, boolArrayColumn.EQ(BoolArray([]bool{true})), `(sub_query."colArrayBool" = $1)`, pq.BoolArray{true})
|
||||
assertProjectionSerialize(t, boolArrayColumn, `sub_query."colArrayBool" AS "colArrayBool"`)
|
||||
|
||||
arrayColumn2 := table1ColBoolArray.From(subQuery)
|
||||
assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_bool"`)
|
||||
assertClauseSerialize(t, arrayColumn2.EQ(BoolArray([]bool{true})), `(sub_query."table1.col_array_bool" = $1)`, pq.BoolArray{true})
|
||||
assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_bool" AS "table1.col_array_bool"`)
|
||||
}
|
||||
|
||||
func TestNewArrayColumnInteger(t *testing.T) {
|
||||
intArrayColumn := ArrayColumn[IntegerExpression]("colArrayInt").From(subQuery)
|
||||
assertClauseSerialize(t, intArrayColumn, `sub_query."colArrayInt"`)
|
||||
assertClauseSerialize(t, intArrayColumn.EQ(Int32Array([]int32{42})), `(sub_query."colArrayInt" = $1)`, pq.Int32Array{42})
|
||||
assertProjectionSerialize(t, intArrayColumn, `sub_query."colArrayInt" AS "colArrayInt"`)
|
||||
|
||||
arrayColumn2 := table1ColIntArray.From(subQuery)
|
||||
assertClauseSerialize(t, arrayColumn2, `sub_query."table1.col_array_int"`)
|
||||
assertClauseSerialize(t, arrayColumn2.EQ(Int32Array([]int32{42})), `(sub_query."table1.col_array_int" = $1)`, pq.Int32Array{42})
|
||||
assertProjectionSerialize(t, arrayColumn2, `sub_query."table1.col_array_int" AS "table1.col_array_int"`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -341,42 +341,3 @@ func (s *complexExpression) serialize(statement StatementType, out *SQLBuilder,
|
|||
func wrap(expressions ...Expression) Expression {
|
||||
return NewFunc("", expressions, nil)
|
||||
}
|
||||
|
||||
type arraySubscriptExpression struct {
|
||||
ExpressionInterfaceImpl
|
||||
array Expression
|
||||
subscript IntegerExpression
|
||||
}
|
||||
|
||||
func (a arraySubscriptExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString("(")
|
||||
}
|
||||
a.array.serialize(statement, out, FallTrough(options)...) // FallTrough here because complexExpression is just a wrapper
|
||||
out.WriteString("[")
|
||||
a.subscript.serialize(statement, out, FallTrough(options)...) // FallTrough here because complexExpression is just a wrapper
|
||||
out.WriteString("]")
|
||||
if !contains(options, NoWrap) {
|
||||
out.WriteString(")")
|
||||
}
|
||||
}
|
||||
|
||||
func arraySubscriptExpr(array Expression, subscript IntegerExpression) Expression {
|
||||
arraySubscriptExpression := &arraySubscriptExpression{array: array, subscript: subscript}
|
||||
arraySubscriptExpression.ExpressionInterfaceImpl.Parent = arraySubscriptExpression
|
||||
|
||||
return arraySubscriptExpression
|
||||
}
|
||||
|
||||
type skipParenthesisWrap struct {
|
||||
Expression
|
||||
}
|
||||
|
||||
func skipWrap(expression Expression) Expression {
|
||||
return &skipParenthesisWrap{expression}
|
||||
}
|
||||
|
||||
// since the expression is a function parameter, there is no need to wrap it in parentheses
|
||||
func (s *skipParenthesisWrap) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||
s.Expression.serialize(statement, out, append(options, NoWrap)...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package jet
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -161,66 +160,6 @@ func Decimal(value string) FloatExpression {
|
|||
return &floatLiteral
|
||||
}
|
||||
|
||||
// ---------------------------------------------------//
|
||||
|
||||
type boolArrayLiteral struct {
|
||||
arrayInterfaceImpl[BoolExpression]
|
||||
literalExpressionImpl
|
||||
}
|
||||
|
||||
func BoolArray(values []bool) ArrayExpression[BoolExpression] {
|
||||
l := boolArrayLiteral{}
|
||||
l.literalExpressionImpl = *literal(pq.BoolArray(values))
|
||||
l.arrayInterfaceImpl.parent = &l
|
||||
|
||||
return &l
|
||||
}
|
||||
|
||||
type integerArrayLiteral struct {
|
||||
arrayInterfaceImpl[IntegerExpression]
|
||||
literalExpressionImpl
|
||||
}
|
||||
|
||||
func Int64Array(values []int64) ArrayExpression[IntegerExpression] {
|
||||
l := integerArrayLiteral{}
|
||||
l.literalExpressionImpl = *literal(pq.Int64Array(values))
|
||||
l.arrayInterfaceImpl.parent = &l
|
||||
return &l
|
||||
}
|
||||
|
||||
func Int32Array(values []int32) ArrayExpression[IntegerExpression] {
|
||||
l := integerArrayLiteral{}
|
||||
l.literalExpressionImpl = *literal(pq.Int32Array(values))
|
||||
l.arrayInterfaceImpl.parent = &l
|
||||
return &l
|
||||
}
|
||||
|
||||
type stringArrayLiteral struct {
|
||||
arrayInterfaceImpl[StringExpression]
|
||||
literalExpressionImpl
|
||||
}
|
||||
|
||||
func StringArray(values []string) ArrayExpression[StringExpression] {
|
||||
l := stringArrayLiteral{}
|
||||
l.literalExpressionImpl = *literal(pq.StringArray(values))
|
||||
l.arrayInterfaceImpl.parent = &l
|
||||
|
||||
return &l
|
||||
}
|
||||
|
||||
type unsafeArrayLiteral[E Expression] struct {
|
||||
arrayInterfaceImpl[E]
|
||||
literalExpressionImpl
|
||||
}
|
||||
|
||||
func UnsafeArray[E LiteralExpression](values []interface{}) ArrayExpression[E] {
|
||||
l := unsafeArrayLiteral[E]{}
|
||||
l.literalExpressionImpl = *literal(pq.Array(values))
|
||||
l.arrayInterfaceImpl.parent = &l
|
||||
|
||||
return &l
|
||||
}
|
||||
|
||||
// ---------------------------------------------------//
|
||||
type stringLiteral struct {
|
||||
stringInterfaceImpl
|
||||
|
|
|
|||
|
|
@ -22,15 +22,6 @@ func BIT_NOT(expr IntegerExpression) IntegerExpression {
|
|||
return newPrefixIntegerOperatorExpression(expr, "~")
|
||||
}
|
||||
|
||||
// ----------- Array operators -------------- //
|
||||
func Any(lhs Expression, op BinaryBoolOp, rhs Expression) BoolExpression {
|
||||
return op(lhs, Func("ANY", rhs))
|
||||
}
|
||||
|
||||
func All(lhs Expression, op BinaryBoolOp, rhs Expression) BoolExpression {
|
||||
return op(lhs, Func("ALL", rhs))
|
||||
}
|
||||
|
||||
//----------- Comparison operators ---------------//
|
||||
|
||||
// EXISTS checks for existence of the rows in subQuery
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@ import (
|
|||
"bytes"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/3rdparty/pq"
|
||||
"github.com/go-jet/jet/v2/internal/utils/is"
|
||||
"github.com/google/uuid"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/3rdparty/pq"
|
||||
"github.com/go-jet/jet/v2/internal/utils/is"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// SQLBuilder generates output SQL
|
||||
|
|
@ -249,8 +248,6 @@ func (s *SQLBuilder) argToString(value interface{}) string {
|
|||
|
||||
case string:
|
||||
return stringQuote(bindVal)
|
||||
case []string:
|
||||
return stringArrayQuote(bindVal)
|
||||
case []byte:
|
||||
return stringQuote(string(bindVal))
|
||||
case uuid.UUID:
|
||||
|
|
@ -278,19 +275,6 @@ func (s *SQLBuilder) argToString(value interface{}) string {
|
|||
}
|
||||
}
|
||||
|
||||
func stringArrayQuote(val []string) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(`'{`)
|
||||
for i := 0; i < len(val); i++ {
|
||||
if i > 0 {
|
||||
sb.WriteString(`, `)
|
||||
}
|
||||
sb.WriteString(stringDoubleQuote(val[i]))
|
||||
}
|
||||
sb.WriteString(`}'`)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func integerTypesToString(value interface{}) string {
|
||||
switch bindVal := value.(type) {
|
||||
case int:
|
||||
|
|
@ -339,7 +323,3 @@ func shouldQuoteIdentifier(identifier string) bool {
|
|||
func stringQuote(value string) string {
|
||||
return `'` + strings.Replace(value, "'", "''", -1) + `'`
|
||||
}
|
||||
|
||||
func stringDoubleQuote(value string) string {
|
||||
return `"` + strings.Replace(value, `"`, `""`, -1) + `"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ type StringExpression interface {
|
|||
BETWEEN(min, max StringExpression) BoolExpression
|
||||
NOT_BETWEEN(min, max StringExpression) BoolExpression
|
||||
|
||||
ANY_EQ(rhs ArrayExpression[StringExpression]) BoolExpression
|
||||
ALL_EQ(rhs ArrayExpression[StringExpression]) BoolExpression
|
||||
|
||||
CONCAT(rhs Expression) StringExpression
|
||||
|
||||
LIKE(pattern StringExpression) BoolExpression
|
||||
|
|
@ -75,14 +72,6 @@ func (s *stringInterfaceImpl) NOT_BETWEEN(min, max StringExpression) BoolExpress
|
|||
return NewBetweenOperatorExpression(s.root, min, max, true)
|
||||
}
|
||||
|
||||
func (i *stringInterfaceImpl) ANY_EQ(rhs ArrayExpression[StringExpression]) BoolExpression {
|
||||
return Any(i.parent, Eq, rhs)
|
||||
}
|
||||
|
||||
func (i *stringInterfaceImpl) ALL_EQ(rhs ArrayExpression[StringExpression]) BoolExpression {
|
||||
return All(i.parent, Eq, rhs)
|
||||
}
|
||||
|
||||
func (s *stringInterfaceImpl) CONCAT(rhs Expression) StringExpression {
|
||||
return newBinaryStringOperatorExpression(s.root, rhs, StringConcatOperator)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,14 +76,6 @@ func TestStringNOT_REGEXP_LIKE(t *testing.T) {
|
|||
assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 NOT REGEXP $1)", "JOHN")
|
||||
}
|
||||
|
||||
func TestStringANY_EQ(t *testing.T) {
|
||||
assertClauseSerialize(t, table2ColStr.ANY_EQ(table1ColStringArray), "(table2.col_str = ANY(table1.col_array_string))")
|
||||
}
|
||||
|
||||
func TestStringALL_EQ(t *testing.T) {
|
||||
assertClauseSerialize(t, table2ColStr.ALL_EQ(table1ColStringArray), "(table2.col_str = ALL(table1.col_array_string))")
|
||||
}
|
||||
|
||||
func TestStringExp(t *testing.T) {
|
||||
assertClauseSerialize(t, StringExp(table2ColFloat), "table2.col_float")
|
||||
assertClauseSerialize(t, StringExp(table2ColFloat).NOT_LIKE(String("abc")), "(table2.col_float NOT LIKE $1)", "abc")
|
||||
|
|
|
|||
|
|
@ -299,6 +299,16 @@ func AssertFileNamesEqual(t *testing.T, dirPath string, fileNames ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
// DeepCopy create deep copy of src
|
||||
func DeepCopy[T any](t require.TestingT, src T) T {
|
||||
var dst T
|
||||
data, err := json.Marshal(src)
|
||||
require.NoError(t, err)
|
||||
err = json.Unmarshal(data, &dst)
|
||||
require.NoError(t, err)
|
||||
return dst
|
||||
}
|
||||
|
||||
// AssertDeepEqual checks if actual and expected objects are deeply equal.
|
||||
func AssertDeepEqual(t require.TestingT, actual, expected interface{}, option ...cmp.Option) {
|
||||
if !assert.True(t, cmp.Equal(actual, expected, option...)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue