Range expression update
* Add Int4 and Int8 integer expression to distinguish int4range and int8range types * Add range functions to range expressions to avoid go template appearing in sql * Compact range integration tests and add range update tests
This commit is contained in:
parent
9d45aaaba5
commit
43fc77ba99
8 changed files with 472 additions and 460 deletions
|
|
@ -470,12 +470,12 @@ func REGEXP_LIKE(stringExp StringExpression, pattern StringExpression, matchType
|
||||||
|
|
||||||
//----------Range Type Functions ----------------------//
|
//----------Range Type Functions ----------------------//
|
||||||
|
|
||||||
// LOWER_BOUND returns range expressions lower bound
|
// LOWER_BOUND returns range expressions lower bound. Returns null if range is empty or the requested bound is infinite.
|
||||||
func LOWER_BOUND[T Expression](rangeExpression Range[T]) T {
|
func LOWER_BOUND[T Expression](rangeExpression Range[T]) T {
|
||||||
return rangeTypeCaster[T](rangeExpression, NewFunc("LOWER", []Expression{rangeExpression}, nil))
|
return rangeTypeCaster[T](rangeExpression, NewFunc("LOWER", []Expression{rangeExpression}, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UPPER_BOUND returns range expressions upper bound
|
// UPPER_BOUND returns range expressions upper bound. Returns null if range is empty or the requested bound is infinite.
|
||||||
func UPPER_BOUND[T Expression](rangeExpression Range[T]) T {
|
func UPPER_BOUND[T Expression](rangeExpression Range[T]) T {
|
||||||
return rangeTypeCaster[T](rangeExpression, NewFunc("UPPER", []Expression{rangeExpression}, nil))
|
return rangeTypeCaster[T](rangeExpression, NewFunc("UPPER", []Expression{rangeExpression}, nil))
|
||||||
}
|
}
|
||||||
|
|
@ -483,18 +483,45 @@ func UPPER_BOUND[T Expression](rangeExpression Range[T]) T {
|
||||||
func rangeTypeCaster[T Expression](rangeExpression Range[T], exp Expression) T {
|
func rangeTypeCaster[T Expression](rangeExpression Range[T], exp Expression) T {
|
||||||
var i Expression
|
var i Expression
|
||||||
switch rangeExpression.(type) {
|
switch rangeExpression.(type) {
|
||||||
|
case Range[Int4Expression], Range[Int8Expression]:
|
||||||
|
i = IntExp(exp)
|
||||||
|
case Range[NumericExpression]:
|
||||||
|
i = FloatExp(exp)
|
||||||
case Range[DateExpression]:
|
case Range[DateExpression]:
|
||||||
i = DateExp(exp)
|
i = DateExp(exp)
|
||||||
case Range[IntegerExpression]:
|
|
||||||
i = IntExp(exp)
|
|
||||||
case Range[TimestampzExpression]:
|
|
||||||
i = TimestampzExp(exp)
|
|
||||||
case Range[TimestampExpression]:
|
case Range[TimestampExpression]:
|
||||||
i = TimestampExp(exp)
|
i = TimestampExp(exp)
|
||||||
|
case Range[TimestampzExpression]:
|
||||||
|
i = TimestampzExp(exp)
|
||||||
}
|
}
|
||||||
return i.(T)
|
return i.(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IS_EMPTY returns true if range is empty
|
||||||
|
func IS_EMPTY[T Expression](rangeExpression Range[T]) BoolExpression {
|
||||||
|
return newBoolFunc("ISEMPTY", rangeExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOWER_INC returns true if lower bound is inclusive. Returns false for empty range.
|
||||||
|
func LOWER_INC[T Expression](rangeExpression Range[T]) BoolExpression {
|
||||||
|
return newBoolFunc("LOWER_INC", rangeExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPPER_INC returns true if upper bound is inclusive. Returns false for empty range.
|
||||||
|
func UPPER_INC[T Expression](rangeExpression Range[T]) BoolExpression {
|
||||||
|
return newBoolFunc("UPPER_INC", rangeExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOWER_INF returns true if upper bound is infinite. Returns false for empty range.
|
||||||
|
func LOWER_INF[T Expression](rangeExpression Range[T]) BoolExpression {
|
||||||
|
return newBoolFunc("LOWER_INF", rangeExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPPER_INF returns true if lower bound is infinite. Returns false for empty range.
|
||||||
|
func UPPER_INF[T Expression](rangeExpression Range[T]) BoolExpression {
|
||||||
|
return newBoolFunc("UPPER_INF", rangeExpression)
|
||||||
|
}
|
||||||
|
|
||||||
//----------Data Type Formatting Functions ----------------------//
|
//----------Data Type Formatting Functions ----------------------//
|
||||||
|
|
||||||
// TO_CHAR converts expression to string with format
|
// TO_CHAR converts expression to string with format
|
||||||
|
|
@ -872,30 +899,30 @@ func Func(name string, expressions ...Expression) Expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NumRange(lowNum, highNum NumericExpression, bounds ...StringExpression) Range[NumericExpression] {
|
func NumRange(lowNum, highNum NumericExpression, bounds ...StringExpression) Range[NumericExpression] {
|
||||||
return RangeExp[NumericExpression](NewFunc("numrange", rangeFuncParamCombiner[NumericExpression](lowNum, highNum, bounds...), nil))
|
return NumRangeExp(NewFunc("numrange", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Int4Range(lowNum, highNum IntegerExpression, bounds ...StringExpression) Range[IntegerExpression] {
|
func Int4Range(lowNum, highNum IntegerExpression, bounds ...StringExpression) Range[Int4Expression] {
|
||||||
return RangeExp[IntegerExpression](NewFunc("int4range", rangeFuncParamCombiner[IntegerExpression](lowNum, highNum, bounds...), nil))
|
return Int4RangeExp(NewFunc("int4range", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Int8Range(lowNum, highNum IntegerExpression, bounds ...StringExpression) Range[IntegerExpression] {
|
func Int8Range(lowNum, highNum Int8Expression, bounds ...StringExpression) Range[Int8Expression] {
|
||||||
return RangeExp[IntegerExpression](NewFunc("int8range", rangeFuncParamCombiner[IntegerExpression](lowNum, highNum, bounds...), nil))
|
return Int8RangeExp(NewFunc("int8range", rangeFuncParamCombiner(lowNum, highNum, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TimestampRange(lowTs, highTs TimestampExpression, bounds ...StringExpression) Range[TimestampExpression] {
|
func TsRange(lowTs, highTs TimestampExpression, bounds ...StringExpression) Range[TimestampExpression] {
|
||||||
return RangeExp[TimestampExpression](NewFunc("tsrange", rangeFuncParamCombiner[TimestampExpression](lowTs, highTs, bounds...), nil))
|
return TsRangeExp(NewFunc("tsrange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TimestampzRange(lowTs, highTs TimestampzExpression, bounds ...StringExpression) Range[TimestampzExpression] {
|
func TstzRange(lowTs, highTs TimestampzExpression, bounds ...StringExpression) Range[TimestampzExpression] {
|
||||||
return RangeExp[TimestampzExpression](NewFunc("tstzrange", rangeFuncParamCombiner[TimestampzExpression](lowTs, highTs, bounds...), nil))
|
return TstzRangeExp(NewFunc("tstzrange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func DateRange(lowTs, highTs DateExpression, bounds ...StringExpression) Range[DateExpression] {
|
func DateRange(lowTs, highTs DateExpression, bounds ...StringExpression) Range[DateExpression] {
|
||||||
return RangeExp[DateExpression](NewFunc("daterange", rangeFuncParamCombiner[DateExpression](lowTs, highTs, bounds...), nil))
|
return DateRangeExp(NewFunc("daterange", rangeFuncParamCombiner(lowTs, highTs, bounds...), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func rangeFuncParamCombiner[T Expression](low, high T, bounds ...StringExpression) []Expression {
|
func rangeFuncParamCombiner(low, high Expression, bounds ...StringExpression) []Expression {
|
||||||
exp := []Expression{low, high}
|
exp := []Expression{low, high}
|
||||||
if len(bounds) != 0 {
|
if len(bounds) != 0 {
|
||||||
exp = append(exp, bounds[0])
|
exp = append(exp, bounds[0])
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,12 @@ type IntegerExpression interface {
|
||||||
BIT_SHIFT_RIGHT(shift IntegerExpression) IntegerExpression
|
BIT_SHIFT_RIGHT(shift IntegerExpression) IntegerExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// additional integer expression subtypes, used in range expressions.
|
||||||
|
type (
|
||||||
|
Int4Expression IntegerExpression
|
||||||
|
Int8Expression IntegerExpression
|
||||||
|
)
|
||||||
|
|
||||||
type integerInterfaceImpl struct {
|
type integerInterfaceImpl struct {
|
||||||
numericExpressionImpl
|
numericExpressionImpl
|
||||||
parent IntegerExpression
|
parent IntegerExpression
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,18 @@ type Range[T Expression] interface {
|
||||||
UNION(rhs Range[T]) Range[T]
|
UNION(rhs Range[T]) Range[T]
|
||||||
INTERSECTION(rhs Range[T]) Range[T]
|
INTERSECTION(rhs Range[T]) Range[T]
|
||||||
DIFFERENCE(rhs Range[T]) Range[T]
|
DIFFERENCE(rhs Range[T]) Range[T]
|
||||||
|
|
||||||
|
UPPER_BOUND() T
|
||||||
|
LOWER_BOUND() T
|
||||||
|
IS_EMPTY() BoolExpression
|
||||||
|
LOWER_INC() BoolExpression
|
||||||
|
UPPER_INC() BoolExpression
|
||||||
|
LOWER_INF() BoolExpression
|
||||||
|
UPPER_INF() BoolExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
type rangeInterfaceImpl[T Expression] struct {
|
type rangeInterfaceImpl[T Expression] struct {
|
||||||
parent Expression
|
parent Range[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rangeInterfaceImpl[T]) EQ(rhs Range[T]) BoolExpression {
|
func (r *rangeInterfaceImpl[T]) EQ(rhs Range[T]) BoolExpression {
|
||||||
|
|
@ -74,6 +82,34 @@ func (r *rangeInterfaceImpl[T]) DIFFERENCE(rhs Range[T]) Range[T] {
|
||||||
return RangeExp[T](Sub(r.parent, rhs))
|
return RangeExp[T](Sub(r.parent, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) UPPER_BOUND() T {
|
||||||
|
return UPPER_BOUND(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) LOWER_BOUND() T {
|
||||||
|
return LOWER_BOUND(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) IS_EMPTY() BoolExpression {
|
||||||
|
return IS_EMPTY(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) LOWER_INC() BoolExpression {
|
||||||
|
return LOWER_INC(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) UPPER_INC() BoolExpression {
|
||||||
|
return UPPER_INC(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) LOWER_INF() BoolExpression {
|
||||||
|
return LOWER_INF(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rangeInterfaceImpl[T]) UPPER_INF() BoolExpression {
|
||||||
|
return UPPER_INF(r.parent)
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------//
|
//---------------------------------------------------//
|
||||||
|
|
||||||
type rangeExpressionWrapper[T Expression] struct {
|
type rangeExpressionWrapper[T Expression] struct {
|
||||||
|
|
@ -93,3 +129,13 @@ func newRangeExpressionWrap[T Expression](expression Expression) Range[T] {
|
||||||
func RangeExp[T Expression](expression Expression) Range[T] {
|
func RangeExp[T Expression](expression Expression) Range[T] {
|
||||||
return newRangeExpressionWrap[T](expression)
|
return newRangeExpressionWrap[T](expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// different range expression wrappers
|
||||||
|
var (
|
||||||
|
Int4RangeExp = RangeExp[Int4Expression]
|
||||||
|
Int8RangeExp = RangeExp[Int8Expression]
|
||||||
|
NumRangeExp = RangeExp[NumericExpression]
|
||||||
|
DateRangeExp = RangeExp[DateExpression]
|
||||||
|
TsRangeExp = RangeExp[TimestampExpression]
|
||||||
|
TstzRangeExp = RangeExp[TimestampzExpression]
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ var (
|
||||||
table1ColTimestampz = TimestampzColumn("col_timestampz")
|
table1ColTimestampz = TimestampzColumn("col_timestampz")
|
||||||
table1ColBool = BoolColumn("col_bool")
|
table1ColBool = BoolColumn("col_bool")
|
||||||
table1ColDate = DateColumn("col_date")
|
table1ColDate = DateColumn("col_date")
|
||||||
table1ColRange = RangeColumn[IntegerExpression]("col_range")
|
table1ColRange = RangeColumn[Int8Expression]("col_range")
|
||||||
)
|
)
|
||||||
var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColRange, table1ColTimestamp, table1ColTimestampz)
|
var table1 = NewTable("db", "table1", "", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColRange, table1ColTimestamp, table1ColTimestampz)
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ var (
|
||||||
table2ColTimestamp = TimestampColumn("col_timestamp")
|
table2ColTimestamp = TimestampColumn("col_timestamp")
|
||||||
table2ColTimestampz = TimestampzColumn("col_timestampz")
|
table2ColTimestampz = TimestampzColumn("col_timestampz")
|
||||||
table2ColDate = DateColumn("col_date")
|
table2ColDate = DateColumn("col_date")
|
||||||
table2ColRange = RangeColumn[IntegerExpression]("col_range")
|
table2ColRange = RangeColumn[Int8Expression]("col_range")
|
||||||
)
|
)
|
||||||
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColRange, table2ColTimestamp, table2ColTimestampz)
|
var table2 = NewTable("db", "table2", "", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColRange, table2ColTimestamp, table2ColTimestampz)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,17 +89,17 @@ type ColumnTimestampzRange = jet.ColumnRange[TimestampzExpression]
|
||||||
// TimestampzRangeColumn creates named range with range column
|
// TimestampzRangeColumn creates named range with range column
|
||||||
var TimestampzRangeColumn = jet.RangeColumn[TimestampzExpression]
|
var TimestampzRangeColumn = jet.RangeColumn[TimestampzExpression]
|
||||||
|
|
||||||
// ColumnInt4Range is interface of SQL int range column
|
// ColumnInt4Range is interface of SQL int4 range column
|
||||||
type ColumnInt4Range = jet.ColumnRange[IntegerExpression]
|
type ColumnInt4Range jet.ColumnRange[jet.Int4Expression]
|
||||||
|
|
||||||
// Int4RangeColumn creates named range with range column
|
// Int4RangeColumn creates named range with range column
|
||||||
var Int4RangeColumn = jet.RangeColumn[IntegerExpression]
|
var Int4RangeColumn = jet.RangeColumn[jet.Int4Expression]
|
||||||
|
|
||||||
// ColumnInt8Range is interface of SQL int range column
|
// ColumnInt8Range is interface of SQL int8 range column
|
||||||
type ColumnInt8Range = jet.ColumnRange[IntegerExpression]
|
type ColumnInt8Range jet.ColumnRange[jet.Int8Expression]
|
||||||
|
|
||||||
// Int8RangeColumn creates named range with range column
|
// Int8RangeColumn creates named range with range column
|
||||||
var Int8RangeColumn = jet.RangeColumn[IntegerExpression]
|
var Int8RangeColumn = jet.RangeColumn[jet.Int8Expression]
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,14 @@ var TimestampzExp = jet.TimestampzExp
|
||||||
// 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.
|
||||||
func RangeExp[T Expression](expression T) jet.Range[T] {
|
var (
|
||||||
return jet.RangeExp[T](expression)
|
Int4RangeExp = jet.Int4RangeExp
|
||||||
}
|
Int8RangeExp = jet.Int8RangeExp
|
||||||
|
NumRangeExp = jet.NumRangeExp
|
||||||
|
DateRangeExp = jet.DateRangeExp
|
||||||
|
TsRangeExp = jet.TsRangeExp
|
||||||
|
TstzRangeExp = jet.TstzRangeExp
|
||||||
|
)
|
||||||
|
|
||||||
// RawArgs is type used to pass optional arguments to Raw method
|
// RawArgs is type used to pass optional arguments to Raw method
|
||||||
type RawArgs = map[string]interface{}
|
type RawArgs = map[string]interface{}
|
||||||
|
|
@ -125,8 +130,8 @@ var (
|
||||||
RawTimestampz = jet.RawTimestampz
|
RawTimestampz = jet.RawTimestampz
|
||||||
RawDate = jet.RawDate
|
RawDate = jet.RawDate
|
||||||
RawNumRange = jet.RawRange[jet.NumericExpression]
|
RawNumRange = jet.RawRange[jet.NumericExpression]
|
||||||
RawInt4Range = jet.RawRange[jet.IntegerExpression]
|
RawInt4Range = jet.RawRange[jet.Int4Expression]
|
||||||
RawInt8Range = jet.RawRange[jet.IntegerExpression]
|
RawInt8Range = jet.RawRange[jet.Int8Expression]
|
||||||
RawTimestampRange = jet.RawRange[jet.TimestampExpression]
|
RawTimestampRange = jet.RawRange[jet.TimestampExpression]
|
||||||
RawTimestampzRange = jet.RawRange[jet.TimestampzExpression]
|
RawTimestampzRange = jet.RawRange[jet.TimestampzExpression]
|
||||||
RawDateRange = jet.RawRange[jet.DateExpression]
|
RawDateRange = jet.RawRange[jet.DateExpression]
|
||||||
|
|
|
||||||
|
|
@ -434,15 +434,16 @@ var CUBE = jet.CUBE
|
||||||
// of the GROUPING function would then be an integer bit mask having 1’s for the arguments which have GROUPING(argument) as 1.
|
// of the GROUPING function would then be an integer bit mask having 1’s for the arguments which have GROUPING(argument) as 1.
|
||||||
var GROUPING = jet.GROUPING
|
var GROUPING = jet.GROUPING
|
||||||
|
|
||||||
|
// range constructor functions
|
||||||
var (
|
var (
|
||||||
// DATE_RANGE constructor function to create a date range
|
// DATE_RANGE constructor function to create a date range
|
||||||
DATE_RANGE = jet.DateRange
|
DATE_RANGE = jet.DateRange
|
||||||
// NUM_Range constructor function to create a numeric range
|
// NUM_RANGE constructor function to create a numeric range
|
||||||
NUM_Range = jet.NumRange
|
NUM_RANGE = jet.NumRange
|
||||||
// TIMESTAMP_RANGE constructor function to create a timestamp range
|
// TS_RANGE constructor function to create a timestamp range
|
||||||
TIMESTAMP_RANGE = jet.TimestampRange
|
TS_RANGE = jet.TsRange
|
||||||
// TIMESTAMPTZ_RANGE constructor function to create a timestampz range
|
// TSTZ_RANGE constructor function to create a timestampz range
|
||||||
TIMESTAMPTZ_RANGE = jet.TimestampzRange
|
TSTZ_RANGE = jet.TstzRange
|
||||||
// INT4_RANGE constructor function to create a int4 range
|
// INT4_RANGE constructor function to create a int4 range
|
||||||
INT4_RANGE = jet.Int4Range
|
INT4_RANGE = jet.Int4Range
|
||||||
// INT8_RANGE constructor function to create a int8 range
|
// INT8_RANGE constructor function to create a int8 range
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"github.com/go-jet/jet/v2/internal/testutils"
|
"github.com/go-jet/jet/v2/internal/testutils"
|
||||||
"github.com/go-jet/jet/v2/qrm"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/jackc/pgtype"
|
"github.com/jackc/pgtype"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
@ -15,59 +15,168 @@ import (
|
||||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRangeTable_DateContainsSingle(t *testing.T) {
|
func TestRangeTableSelect(t *testing.T) {
|
||||||
skipForCockroachDB(t)
|
skipForCockroachDB(t)
|
||||||
expectedSQL := `
|
|
||||||
SELECT DISTINCT sample_ranges.date_range AS "sample_ranges.date_range",
|
int4Range := INT4_RANGE(Int(11), Int(20))
|
||||||
|
int8Range := INT8_RANGE(Int(100), Int(250), String("[)"))
|
||||||
|
numRange := NUM_RANGE(Int(11), Float(22.22))
|
||||||
|
dateRange := DATE_RANGE(Date(2010, 10, 1), DateExp(PLUS_INFINITY))
|
||||||
|
tsRange := TS_RANGE(
|
||||||
|
Timestamp(2020, 02, 01, 0, 0, 0),
|
||||||
|
Timestamp(2020, 10, 01, 0, 0, 0),
|
||||||
|
)
|
||||||
|
tstzRange := TSTZ_RANGE(
|
||||||
|
TimestampzExp(MINUS_INFINITY),
|
||||||
|
TimestampzT(time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC)),
|
||||||
|
)
|
||||||
|
|
||||||
|
query := SELECT(
|
||||||
|
SampleRanges.AllColumns,
|
||||||
|
|
||||||
|
SampleRanges.Int4Range.EQ(SampleRanges.Int4Range).AS("sample.int4eq"),
|
||||||
|
SampleRanges.Int8Range.EQ(int8Range).AS("sample.int8eq"),
|
||||||
|
SampleRanges.Int4Range.NOT_EQ(int4Range).AS("sample.int4neq"),
|
||||||
|
SampleRanges.NumRange.LT(numRange).IS_TRUE().AS("sample.num_lt"),
|
||||||
|
SampleRanges.DateRange.LT_EQ(dateRange).IS_FALSE().AS("sample.date_lteq"),
|
||||||
|
SampleRanges.TimestampRange.GT(tsRange).AS("sample.ts_gt"),
|
||||||
|
SampleRanges.TimestampzRange.GT_EQ(tstzRange).AS("sample.tstz_gteq"),
|
||||||
|
SampleRanges.Int4Range.CONTAINS(Int32(22)).AS("sample.int4cont"),
|
||||||
|
SampleRanges.Int8Range.CONTAINS(Int64(75364)).AS("sample.int8cont"),
|
||||||
|
SampleRanges.Int8Range.CONTAINS_RANGE(int8Range).AS("sample.int8cont_range"),
|
||||||
|
SampleRanges.NumRange.OVERLAP(numRange).AS("sample.num_overlap"),
|
||||||
|
SampleRanges.DateRange.UNION(dateRange).AS("sample.date_union"),
|
||||||
|
SampleRanges.TimestampRange.INTERSECTION(tsRange).AS("sample.ts_ints"),
|
||||||
|
SampleRanges.TimestampzRange.DIFFERENCE(tstzRange).AS("sample.tstz_diff"),
|
||||||
|
SampleRanges.Int4Range.UPPER_BOUND().ADD(Int(5)).AS("sample.int4_upper"),
|
||||||
|
SampleRanges.Int8Range.LOWER_BOUND().SUB(Int(12)).AS("sample.int8_lower"),
|
||||||
|
LOWER_BOUND[DateExpression](SampleRanges.DateRange),
|
||||||
|
UPPER_BOUND[NumericExpression](SampleRanges.NumRange).AS("sample.num_upper"),
|
||||||
|
SampleRanges.TimestampRange.UPPER_BOUND(),
|
||||||
|
SampleRanges.DateRange.IS_EMPTY().AS("sample.date_empty"),
|
||||||
|
SampleRanges.TimestampRange.LOWER_INC().AS("sample.ts_low_inc"),
|
||||||
|
SampleRanges.TimestampzRange.UPPER_INC().AS("sample.tstz_up_inc"),
|
||||||
|
SampleRanges.TimestampRange.LOWER_INF().AS("sample.ts_low_inf"),
|
||||||
|
SampleRanges.TimestampzRange.UPPER_INF().AS("sample.tstz_up_inf"),
|
||||||
|
|
||||||
|
RawInt4Range("'[1,2]'").EQ(int4Range),
|
||||||
|
RawInt8Range("int8range(15, 25)").EQ(int8Range),
|
||||||
|
RawNumRange("numrange(20.0, 30.0)").NOT_EQ(numRange),
|
||||||
|
).FROM(
|
||||||
|
SampleRanges,
|
||||||
|
).WHERE(
|
||||||
|
SampleRanges.DateRange.CONTAINS(Date(2023, 12, 12)),
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, query, `
|
||||||
|
SELECT sample_ranges.date_range AS "sample_ranges.date_range",
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
||||||
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range"
|
sample_ranges.num_range AS "sample_ranges.num_range",
|
||||||
|
(sample_ranges.int4_range = sample_ranges.int4_range) AS "sample.int4eq",
|
||||||
|
(sample_ranges.int8_range = int8range($1, $2, $3::text)) AS "sample.int8eq",
|
||||||
|
(sample_ranges.int4_range != int4range($4, $5)) AS "sample.int4neq",
|
||||||
|
(sample_ranges.num_range < numrange($6, $7)) IS TRUE AS "sample.num_lt",
|
||||||
|
(sample_ranges.date_range <= daterange($8::date, $9)) IS FALSE AS "sample.date_lteq",
|
||||||
|
(sample_ranges.timestamp_range > tsrange($10::timestamp without time zone, $11::timestamp without time zone)) AS "sample.ts_gt",
|
||||||
|
(sample_ranges.timestampz_range >= tstzrange($12, $13::timestamp with time zone)) AS "sample.tstz_gteq",
|
||||||
|
(sample_ranges.int4_range @> $14::integer) AS "sample.int4cont",
|
||||||
|
(sample_ranges.int8_range @> $15::bigint) AS "sample.int8cont",
|
||||||
|
(sample_ranges.int8_range @> int8range($16, $17, $18::text)) AS "sample.int8cont_range",
|
||||||
|
(sample_ranges.num_range && numrange($19, $20)) AS "sample.num_overlap",
|
||||||
|
(sample_ranges.date_range + daterange($21::date, $22)) AS "sample.date_union",
|
||||||
|
(sample_ranges.timestamp_range * tsrange($23::timestamp without time zone, $24::timestamp without time zone)) AS "sample.ts_ints",
|
||||||
|
(sample_ranges.timestampz_range - tstzrange($25, $26::timestamp with time zone)) AS "sample.tstz_diff",
|
||||||
|
(UPPER(sample_ranges.int4_range) + $27) AS "sample.int4_upper",
|
||||||
|
(LOWER(sample_ranges.int8_range) - $28) AS "sample.int8_lower",
|
||||||
|
LOWER(sample_ranges.date_range),
|
||||||
|
UPPER(sample_ranges.num_range) AS "sample.num_upper",
|
||||||
|
UPPER(sample_ranges.timestamp_range),
|
||||||
|
ISEMPTY(sample_ranges.date_range) AS "sample.date_empty",
|
||||||
|
LOWER_INC(sample_ranges.timestamp_range) AS "sample.ts_low_inc",
|
||||||
|
UPPER_INC(sample_ranges.timestampz_range) AS "sample.tstz_up_inc",
|
||||||
|
LOWER_INF(sample_ranges.timestamp_range) AS "sample.ts_low_inf",
|
||||||
|
UPPER_INF(sample_ranges.timestampz_range) AS "sample.tstz_up_inf",
|
||||||
|
('[1,2]') = int4range($29, $30),
|
||||||
|
(int8range(15, 25)) = int8range($31, $32, $33::text),
|
||||||
|
(numrange(20.0, 30.0)) != numrange($34, $35)
|
||||||
FROM test_sample.sample_ranges
|
FROM test_sample.sample_ranges
|
||||||
WHERE sample_ranges.date_range @> '2023-12-12'::date;
|
WHERE sample_ranges.date_range @> $36::date;
|
||||||
`
|
`)
|
||||||
|
|
||||||
query := SELECT(SampleRanges.AllColumns).
|
type sample struct {
|
||||||
DISTINCT().
|
model.SampleRanges
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.DateRange.CONTAINS(Date(2023, 12, 12)))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "2023-12-12")
|
Int4Eq bool
|
||||||
|
Int8Eq bool
|
||||||
sample := model.SampleRanges{}
|
Int4Neq bool
|
||||||
err := query.Query(db, &sample)
|
NumLt bool
|
||||||
|
DateLtEq bool
|
||||||
|
TsGt bool
|
||||||
|
TsTzGtEq bool
|
||||||
|
Int4Cont bool
|
||||||
|
Int8Cont bool
|
||||||
|
Int8ContRange bool
|
||||||
|
NumOverlap bool
|
||||||
|
DateUnion pgtype.Daterange
|
||||||
|
TsInts pgtype.Tsrange
|
||||||
|
TsTzDiff pgtype.Tstzrange
|
||||||
|
Int4Upper int32
|
||||||
|
Int8Lower int64
|
||||||
|
NumUpper float64
|
||||||
|
DateEmpty bool
|
||||||
|
TsLowInc bool
|
||||||
|
TsTzUpInc bool
|
||||||
|
TsLowInf bool
|
||||||
|
TsTzUpInf bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var dest sample
|
||||||
|
err := query.Query(db, &dest)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expectedRow := model.SampleRanges{
|
expectedRow := sample{
|
||||||
DateRange: pgtype.Daterange{
|
SampleRanges: sampleRangeRow,
|
||||||
|
Int4Eq: true,
|
||||||
|
Int8Eq: false,
|
||||||
|
Int4Neq: false,
|
||||||
|
NumLt: false,
|
||||||
|
DateLtEq: true,
|
||||||
|
TsGt: false,
|
||||||
|
TsTzGtEq: true,
|
||||||
|
Int4Cont: false,
|
||||||
|
Int8Cont: false,
|
||||||
|
Int8ContRange: false,
|
||||||
|
NumOverlap: false,
|
||||||
|
DateUnion: pgtype.Daterange{
|
||||||
Lower: pgtype.Date{
|
Lower: pgtype.Date{
|
||||||
Time: time.Date(2023, 9, 25, 0, 0, 0, 0, time.UTC),
|
Time: time.Date(2010, 10, 1, 0, 0, 0, 0, time.UTC),
|
||||||
Status: pgtype.Present,
|
Status: pgtype.Present,
|
||||||
},
|
},
|
||||||
Upper: pgtype.Date{
|
Upper: pgtype.Date{
|
||||||
Time: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
Status: pgtype.Present,
|
||||||
|
InfinityModifier: pgtype.Infinity,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
TsInts: pgtype.Tsrange{
|
||||||
|
Lower: pgtype.Timestamp{
|
||||||
|
Time: time.Date(2020, 02, 01, 0, 0, 0, 0, time.UTC),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Timestamp{
|
||||||
|
Time: time.Date(2020, 10, 01, 0, 0, 0, 0, time.UTC),
|
||||||
Status: pgtype.Present,
|
Status: pgtype.Present,
|
||||||
},
|
},
|
||||||
LowerType: pgtype.Inclusive,
|
LowerType: pgtype.Inclusive,
|
||||||
UpperType: pgtype.Exclusive,
|
UpperType: pgtype.Exclusive,
|
||||||
Status: pgtype.Present,
|
Status: pgtype.Present,
|
||||||
},
|
},
|
||||||
TimestampRange: pgtype.Tsrange{
|
TsTzDiff: pgtype.Tstzrange{
|
||||||
Lower: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2021, 01, 01, 15, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Inclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
TimestampzRange: pgtype.Tstzrange{
|
|
||||||
Lower: pgtype.Timestamptz{
|
Lower: pgtype.Timestamptz{
|
||||||
Time: time.Date(2024, 05, 07, 15, 0, 0, 0, time.FixedZone("", 0)),
|
Time: time.Date(2024, 05, 07, 15, 0, 0, 0, time.FixedZone("", 0)),
|
||||||
Status: pgtype.Present,
|
Status: pgtype.Present,
|
||||||
|
|
@ -80,410 +189,85 @@ WHERE sample_ranges.date_range @> '2023-12-12'::date;
|
||||||
UpperType: pgtype.Exclusive,
|
UpperType: pgtype.Exclusive,
|
||||||
Status: pgtype.Present,
|
Status: pgtype.Present,
|
||||||
},
|
},
|
||||||
Int4Range: pgtype.Int4range{
|
Int4Upper: 25,
|
||||||
Lower: pgtype.Int4{
|
Int8Lower: 188,
|
||||||
Int: 11,
|
NumUpper: 5000,
|
||||||
Status: pgtype.Present,
|
DateEmpty: false,
|
||||||
},
|
TsLowInc: true,
|
||||||
Upper: pgtype.Int4{
|
TsTzUpInc: false,
|
||||||
Int: 20,
|
TsLowInf: false,
|
||||||
Status: pgtype.Present,
|
TsTzUpInf: false,
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Int8Range: pgtype.Int8range{
|
|
||||||
Lower: pgtype.Int8{
|
|
||||||
Int: 200,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Int8{
|
|
||||||
Int: 2450,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
NumRange: pgtype.Numrange{
|
|
||||||
Lower: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(2),
|
|
||||||
Exp: 3,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(5),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
Exp: 3,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testutils.AssertDeepEqual(t, sample, expectedRow, cmp.AllowUnexported(big.Int{}))
|
testutils.AssertDeepEqual(t, dest, expectedRow, cmp.AllowUnexported(big.Int{}))
|
||||||
requireLogged(t, query)
|
requireLogged(t, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRangeTable_IntContainsRange(t *testing.T) {
|
func TestRangeSelectColumnsFromSubQuery(t *testing.T) {
|
||||||
skipForCockroachDB(t)
|
|
||||||
expectedSQL := `
|
subQuery := SELECT(
|
||||||
SELECT DISTINCT sample_ranges.date_range AS "sample_ranges.date_range",
|
SampleRanges.AllColumns,
|
||||||
|
SampleRanges.Int4Range.AS("range4"),
|
||||||
|
).FROM(
|
||||||
|
SampleRanges,
|
||||||
|
).AsTable("sub_query")
|
||||||
|
|
||||||
|
int4Range := Int4RangeColumn("range4").From(subQuery)
|
||||||
|
|
||||||
|
stmt := SELECT(
|
||||||
|
subQuery.AllColumns(),
|
||||||
|
int4Range,
|
||||||
|
).FROM(
|
||||||
|
subQuery,
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
SELECT sub_query."sample_ranges.date_range" AS "sample_ranges.date_range",
|
||||||
|
sub_query."sample_ranges.timestamp_range" AS "sample_ranges.timestamp_range",
|
||||||
|
sub_query."sample_ranges.timestampz_range" AS "sample_ranges.timestampz_range",
|
||||||
|
sub_query."sample_ranges.int4_range" AS "sample_ranges.int4_range",
|
||||||
|
sub_query."sample_ranges.int8_range" AS "sample_ranges.int8_range",
|
||||||
|
sub_query."sample_ranges.num_range" AS "sample_ranges.num_range",
|
||||||
|
sub_query.range4 AS "range4",
|
||||||
|
sub_query.range4 AS "range4"
|
||||||
|
FROM (
|
||||||
|
SELECT sample_ranges.date_range AS "sample_ranges.date_range",
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
||||||
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range"
|
sample_ranges.num_range AS "sample_ranges.num_range",
|
||||||
|
sample_ranges.int4_range AS "range4"
|
||||||
FROM test_sample.sample_ranges
|
FROM test_sample.sample_ranges
|
||||||
WHERE sample_ranges.int4_range @> int4range(12, 18, '[)'::text);
|
) AS sub_query;
|
||||||
`
|
`)
|
||||||
|
|
||||||
query := SELECT(SampleRanges.AllColumns).
|
var dest struct {
|
||||||
DISTINCT().
|
model.SampleRanges
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.Int4Range.CONTAINS_RANGE(INT4_RANGE(Int(12), Int(18), String("[)"))))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(12), int64(18), "[)")
|
Range4 pgtype.Int4range
|
||||||
|
}
|
||||||
|
|
||||||
sample := model.SampleRanges{}
|
err := stmt.Query(db, &dest)
|
||||||
err := query.Query(db, &sample)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
testutils.AssertDeepEqual(t, dest.SampleRanges.Int4Range, sampleRangeRow.Int4Range)
|
||||||
expectedRow := model.SampleRanges{
|
testutils.AssertDeepEqual(t, dest.SampleRanges.Int8Range, sampleRangeRow.Int8Range)
|
||||||
DateRange: pgtype.Daterange{
|
testutils.AssertDeepEqual(t, dest.Range4, sampleRangeRow.Int4Range)
|
||||||
Lower: pgtype.Date{
|
|
||||||
Time: time.Date(2023, 9, 25, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Date{
|
|
||||||
Time: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
TimestampRange: pgtype.Tsrange{
|
|
||||||
Lower: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2021, 01, 01, 15, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Inclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
TimestampzRange: pgtype.Tstzrange{
|
|
||||||
Lower: pgtype.Timestamptz{
|
|
||||||
Time: time.Date(2024, 05, 07, 15, 0, 0, 0, time.FixedZone("", 0)),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Timestamptz{
|
|
||||||
Time: time.Date(2024, 10, 11, 14, 0, 0, 0, time.FixedZone("", 0)),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Int4Range: pgtype.Int4range{
|
|
||||||
Lower: pgtype.Int4{
|
|
||||||
Int: 11,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Int4{
|
|
||||||
Int: 20,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Int8Range: pgtype.Int8range{
|
|
||||||
Lower: pgtype.Int8{
|
|
||||||
Int: 200,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Int8{
|
|
||||||
Int: 2450,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
NumRange: pgtype.Numrange{
|
|
||||||
Lower: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(2),
|
|
||||||
Exp: 3,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(5),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
Exp: 3,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testutils.AssertDeepEqual(t, sample, expectedRow, cmp.AllowUnexported(big.Int{}))
|
|
||||||
requireLogged(t, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRangeTable_TimestampContainsRange(t *testing.T) {
|
|
||||||
skipForCockroachDB(t)
|
|
||||||
expectedSQL := `
|
|
||||||
SELECT DISTINCT sample_ranges.date_range AS "sample_ranges.date_range",
|
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
|
||||||
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range"
|
|
||||||
FROM test_sample.sample_ranges
|
|
||||||
WHERE sample_ranges.timestamp_range @> tsrange('2020-02-01 00:00:00'::timestamp without time zone, '2020-10-01 00:00:00'::timestamp without time zone, '[)'::text);
|
|
||||||
`
|
|
||||||
|
|
||||||
query := SELECT(SampleRanges.AllColumns).
|
|
||||||
DISTINCT().
|
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.TimestampRange.CONTAINS_RANGE(TIMESTAMP_RANGE(Timestamp(2020, 02, 01, 0, 0, 0), Timestamp(2020, 10, 01, 0, 0, 0), String("[)"))))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "2020-02-01 00:00:00", "2020-10-01 00:00:00", "[)")
|
|
||||||
|
|
||||||
sample := model.SampleRanges{}
|
|
||||||
err := query.Query(db, &sample)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedRow := model.SampleRanges{
|
|
||||||
DateRange: pgtype.Daterange{
|
|
||||||
Lower: pgtype.Date{
|
|
||||||
Time: time.Date(2023, 9, 25, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Date{
|
|
||||||
Time: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
TimestampRange: pgtype.Tsrange{
|
|
||||||
Lower: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Timestamp{
|
|
||||||
Time: time.Date(2021, 01, 01, 15, 0, 0, 0, time.UTC),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Inclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
TimestampzRange: pgtype.Tstzrange{
|
|
||||||
Lower: pgtype.Timestamptz{
|
|
||||||
Time: time.Date(2024, 05, 07, 15, 0, 0, 0, time.FixedZone("", 0)),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Timestamptz{
|
|
||||||
Time: time.Date(2024, 10, 11, 14, 0, 0, 0, time.FixedZone("", 0)),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Int4Range: pgtype.Int4range{
|
|
||||||
Lower: pgtype.Int4{
|
|
||||||
Int: 11,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Int4{
|
|
||||||
Int: 20,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Int8Range: pgtype.Int8range{
|
|
||||||
Lower: pgtype.Int8{
|
|
||||||
Int: 200,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Int8{
|
|
||||||
Int: 2450,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
NumRange: pgtype.Numrange{
|
|
||||||
Lower: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(2),
|
|
||||||
Exp: 3,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
Upper: pgtype.Numeric{
|
|
||||||
Int: big.NewInt(5),
|
|
||||||
Status: pgtype.Present,
|
|
||||||
Exp: 3,
|
|
||||||
},
|
|
||||||
LowerType: pgtype.Inclusive,
|
|
||||||
UpperType: pgtype.Exclusive,
|
|
||||||
Status: pgtype.Present,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testutils.AssertDeepEqual(t, sample, expectedRow, cmp.AllowUnexported(big.Int{}))
|
|
||||||
requireLogged(t, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRangeTable_ContainsOutOfRange(t *testing.T) {
|
|
||||||
skipForCockroachDB(t)
|
|
||||||
expectedSQL := `
|
|
||||||
SELECT DISTINCT sample_ranges.date_range AS "sample_ranges.date_range",
|
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
|
||||||
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range"
|
|
||||||
FROM test_sample.sample_ranges
|
|
||||||
WHERE sample_ranges.int4_range @> int4range(12, 30, '[)'::text);
|
|
||||||
`
|
|
||||||
|
|
||||||
query := SELECT(SampleRanges.AllColumns).
|
|
||||||
DISTINCT().
|
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.Int4Range.CONTAINS_RANGE(INT4_RANGE(Int(12), Int(30), String("[)"))))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(12), int64(30), "[)")
|
|
||||||
|
|
||||||
sample := model.SampleRanges{}
|
|
||||||
err := query.Query(db, &sample)
|
|
||||||
|
|
||||||
require.ErrorIs(t, err, qrm.ErrNoRows)
|
|
||||||
requireLogged(t, query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRangeTable_InsertColumn(t *testing.T) {
|
func TestRangeTable_InsertColumn(t *testing.T) {
|
||||||
skipForCockroachDB(t)
|
skipForCockroachDB(t)
|
||||||
|
|
||||||
insertQuery := SampleRanges.INSERT(SampleRanges.AllColumns).
|
|
||||||
VALUES(
|
|
||||||
DATE_RANGE(
|
|
||||||
Date(2010, 01, 01),
|
|
||||||
Date(2014, 01, 01),
|
|
||||||
String("[)"),
|
|
||||||
),
|
|
||||||
DEFAULT,
|
|
||||||
TIMESTAMPTZ_RANGE(
|
|
||||||
TimestampzT(time.Date(2010, 01, 01, 23, 0, 0, 0, time.UTC)),
|
|
||||||
TimestampzT(time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC)),
|
|
||||||
String("[)"),
|
|
||||||
),
|
|
||||||
INT4_RANGE(Int(64), Int(128), String("[]")),
|
|
||||||
INT8_RANGE(Int(1024), Int(2048), String("[]")),
|
|
||||||
DEFAULT,
|
|
||||||
).
|
|
||||||
RETURNING(SampleRanges.AllColumns)
|
|
||||||
|
|
||||||
expectedQuery := `
|
|
||||||
INSERT INTO test_sample.sample_ranges (date_range, timestamp_range, timestampz_range, int4_range, int8_range, num_range)
|
|
||||||
VALUES (daterange('2010-01-01'::date, '2014-01-01'::date, '[)'::text), DEFAULT, tstzrange('2010-01-01 23:00:00Z'::timestamp with time zone, '2014-01-01 15:00:00Z'::timestamp with time zone, '[)'::text), int4range(64, 128, '[]'::text), int8range(1024, 2048, '[]'::text), DEFAULT)
|
|
||||||
RETURNING sample_ranges.date_range AS "sample_ranges.date_range",
|
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
|
||||||
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range";
|
|
||||||
`
|
|
||||||
testutils.AssertDebugStatementSql(t, insertQuery, expectedQuery,
|
|
||||||
"2010-01-01", "2014-01-01", "[)",
|
|
||||||
time.Date(2010, 01, 01, 23, 0, 0, 0, time.UTC), time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC), "[)",
|
|
||||||
int64(64), int64(128), "[]",
|
|
||||||
int64(1024), int64(2048), "[]",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRangeTable_UpperBound(t *testing.T) {
|
|
||||||
skipForCockroachDB(t)
|
|
||||||
|
|
||||||
expectedSQL := `
|
|
||||||
SELECT UPPER(sample_ranges.date_range)
|
|
||||||
FROM test_sample.sample_ranges
|
|
||||||
WHERE sample_ranges.date_range @> '2023-12-12'::date;
|
|
||||||
`
|
|
||||||
|
|
||||||
query := SELECT(UPPER_BOUND[DateExpression](SampleRanges.DateRange)).
|
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.DateRange.CONTAINS(Date(2023, 12, 12)))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "2023-12-12")
|
|
||||||
|
|
||||||
var date time.Time
|
|
||||||
err := query.Query(db, &date)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedYear := 2024
|
|
||||||
expectedMonth := time.February
|
|
||||||
expectedDay := 10
|
|
||||||
if expectedYear != date.Year() || expectedMonth != date.Month() || expectedDay != date.Day() {
|
|
||||||
t.Errorf("expected: 2024-02-10 got: %s", date.Format("2006-01-02"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRangeTable_LowerBound(t *testing.T) {
|
|
||||||
skipForCockroachDB(t)
|
|
||||||
|
|
||||||
expectedSQL := `
|
|
||||||
SELECT LOWER(sample_ranges.date_range)
|
|
||||||
FROM test_sample.sample_ranges
|
|
||||||
WHERE sample_ranges.date_range @> '2023-12-12'::date;
|
|
||||||
`
|
|
||||||
|
|
||||||
query := SELECT(LOWER_BOUND[DateExpression](SampleRanges.DateRange)).
|
|
||||||
FROM(SampleRanges).
|
|
||||||
WHERE(SampleRanges.DateRange.CONTAINS(Date(2023, 12, 12)))
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "2023-12-12")
|
|
||||||
|
|
||||||
var date time.Time
|
|
||||||
err := query.Query(db, &date)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedYear := 2023
|
|
||||||
expectedMonth := time.September
|
|
||||||
expectedDay := 25
|
|
||||||
if expectedYear != date.Year() || expectedMonth != date.Month() || expectedDay != date.Day() {
|
|
||||||
t.Errorf("expected: 2023-09-25 got: %s", date.Format("2006-01-02"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRangeTable_InsertInfinite(t *testing.T) {
|
|
||||||
skipForCockroachDB(t)
|
|
||||||
|
|
||||||
insertQuery := SampleRanges.INSERT(SampleRanges.AllColumns).
|
insertQuery := SampleRanges.INSERT(SampleRanges.AllColumns).
|
||||||
VALUES(
|
VALUES(
|
||||||
DATE_RANGE(
|
DATE_RANGE(
|
||||||
Date(2010, 01, 01),
|
Date(2010, 01, 01),
|
||||||
DateExp(PLUS_INFINITY),
|
DateExp(PLUS_INFINITY),
|
||||||
String("[)"),
|
String("()"),
|
||||||
),
|
),
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
TIMESTAMPTZ_RANGE(
|
TSTZ_RANGE(
|
||||||
TimestampzExp(MINUS_INFINITY),
|
TimestampzExp(MINUS_INFINITY),
|
||||||
TimestampzT(time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC)),
|
TimestampzT(time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC)),
|
||||||
String("[)"),
|
String("[)"),
|
||||||
|
|
@ -492,11 +276,14 @@ func TestRangeTable_InsertInfinite(t *testing.T) {
|
||||||
INT8_RANGE(Int(1024), Int(2048), String("[]")),
|
INT8_RANGE(Int(1024), Int(2048), String("[]")),
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
).
|
).
|
||||||
RETURNING(SampleRanges.AllColumns)
|
MODEL(
|
||||||
|
sampleRangeRow,
|
||||||
|
).RETURNING(SampleRanges.AllColumns)
|
||||||
|
|
||||||
expectedQuery := `
|
expectedQuery := `
|
||||||
INSERT INTO test_sample.sample_ranges (date_range, timestamp_range, timestampz_range, int4_range, int8_range, num_range)
|
INSERT INTO test_sample.sample_ranges (date_range, timestamp_range, timestampz_range, int4_range, int8_range, num_range)
|
||||||
VALUES (daterange('2010-01-01'::date, 'infinity', '[)'::text), DEFAULT, tstzrange('-infinity', '2014-01-01 15:00:00Z'::timestamp with time zone, '[)'::text), int4range(64, 128, '[]'::text), int8range(1024, 2048, '[]'::text), DEFAULT)
|
VALUES (daterange('2010-01-01'::date, 'infinity', '()'::text), DEFAULT, tstzrange('-infinity', '2014-01-01 15:00:00Z'::timestamp with time zone, '[)'::text), int4range(64, 128, '[]'::text), int8range(1024, 2048, '[]'::text), DEFAULT),
|
||||||
|
('[2023-09-25,2024-02-10)', '[2020-01-01 00:00:00,2021-01-01 15:00:00]', '[2024-05-07 15:00:00Z,2024-10-11 14:00:00Z)', '[11,20)', '[200,2450)', '[2e3,5e3)')
|
||||||
RETURNING sample_ranges.date_range AS "sample_ranges.date_range",
|
RETURNING sample_ranges.date_range AS "sample_ranges.date_range",
|
||||||
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
||||||
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
||||||
|
|
@ -504,11 +291,151 @@ RETURNING sample_ranges.date_range AS "sample_ranges.date_range",
|
||||||
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
||||||
sample_ranges.num_range AS "sample_ranges.num_range";
|
sample_ranges.num_range AS "sample_ranges.num_range";
|
||||||
`
|
`
|
||||||
|
testutils.AssertDebugStatementSql(t, insertQuery, expectedQuery)
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, insertQuery, expectedQuery,
|
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
|
||||||
"2010-01-01", "infinity", "[)",
|
var dest []model.SampleRanges
|
||||||
"-infinity", time.Date(2014, 01, 01, 15, 0, 0, 0, time.UTC), "[)",
|
err := insertQuery.Query(tx, &dest)
|
||||||
int64(64), int64(128), "[]",
|
require.NoError(t, err)
|
||||||
int64(1024), int64(2048), "[]",
|
require.Len(t, dest, 2)
|
||||||
)
|
testutils.AssertDeepEqual(t, sampleRangeRow, dest[1], cmp.AllowUnexported(big.Int{}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRangeTableUpdate(t *testing.T) {
|
||||||
|
skipForCockroachDB(t)
|
||||||
|
|
||||||
|
t.Run("using model", func(t *testing.T) {
|
||||||
|
stmt := SampleRanges.UPDATE(SampleRanges.AllColumns).
|
||||||
|
MODEL(sampleRangeRow).
|
||||||
|
WHERE(SampleRanges.TimestampRange.LOWER_INF().IS_FALSE()).
|
||||||
|
RETURNING(SampleRanges.AllColumns)
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
UPDATE test_sample.sample_ranges
|
||||||
|
SET (date_range, timestamp_range, timestampz_range, int4_range, int8_range, num_range) = ($1, $2, $3, $4, $5, $6)
|
||||||
|
WHERE LOWER_INF(sample_ranges.timestamp_range) IS FALSE
|
||||||
|
RETURNING sample_ranges.date_range AS "sample_ranges.date_range",
|
||||||
|
sample_ranges.timestamp_range AS "sample_ranges.timestamp_range",
|
||||||
|
sample_ranges.timestampz_range AS "sample_ranges.timestampz_range",
|
||||||
|
sample_ranges.int4_range AS "sample_ranges.int4_range",
|
||||||
|
sample_ranges.int8_range AS "sample_ranges.int8_range",
|
||||||
|
sample_ranges.num_range AS "sample_ranges.num_range";
|
||||||
|
`)
|
||||||
|
|
||||||
|
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
|
||||||
|
var dest []model.SampleRanges
|
||||||
|
|
||||||
|
err := stmt.Query(tx, &dest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, dest, 1)
|
||||||
|
testutils.AssertDeepEqual(t, sampleRangeRow, dest[0], cmp.AllowUnexported(big.Int{}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("update using SET", func(t *testing.T) {
|
||||||
|
stmt := SampleRanges.UPDATE().
|
||||||
|
SET(
|
||||||
|
SampleRanges.Int4Range.SET(INT4_RANGE(Int32(-12), Int32(78))),
|
||||||
|
SampleRanges.Int8Range.SET(INT8_RANGE(Int64(-1200), Int64(7800))),
|
||||||
|
).
|
||||||
|
WHERE(
|
||||||
|
SampleRanges.TimestampzRange.LOWER_BOUND().GT(NOW()),
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, `
|
||||||
|
UPDATE test_sample.sample_ranges
|
||||||
|
SET int4_range = int4range(-12::integer, 78::integer),
|
||||||
|
int8_range = int8range(-1200::bigint, 7800::bigint)
|
||||||
|
WHERE LOWER(sample_ranges.timestampz_range) > NOW();
|
||||||
|
`)
|
||||||
|
|
||||||
|
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
|
||||||
|
testutils.AssertExec(t, stmt, tx, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var sampleRangeRow = model.SampleRanges{
|
||||||
|
DateRange: pgtype.Daterange{
|
||||||
|
Lower: pgtype.Date{
|
||||||
|
Time: time.Date(2023, 9, 25, 0, 0, 0, 0, time.UTC),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Date{
|
||||||
|
Time: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
TimestampRange: pgtype.Tsrange{
|
||||||
|
Lower: pgtype.Timestamp{
|
||||||
|
Time: time.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Timestamp{
|
||||||
|
Time: time.Date(2021, 01, 01, 15, 0, 0, 0, time.UTC),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Inclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
TimestampzRange: pgtype.Tstzrange{
|
||||||
|
Lower: pgtype.Timestamptz{
|
||||||
|
Time: time.Date(2024, 05, 07, 15, 0, 0, 0, time.FixedZone("", 0)),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Timestamptz{
|
||||||
|
Time: time.Date(2024, 10, 11, 14, 0, 0, 0, time.FixedZone("", 0)),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Int4Range: pgtype.Int4range{
|
||||||
|
Lower: pgtype.Int4{
|
||||||
|
Int: 11,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Int4{
|
||||||
|
Int: 20,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Int8Range: pgtype.Int8range{
|
||||||
|
Lower: pgtype.Int8{
|
||||||
|
Int: 200,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Int8{
|
||||||
|
Int: 2450,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
NumRange: pgtype.Numrange{
|
||||||
|
Lower: pgtype.Numeric{
|
||||||
|
Int: big.NewInt(2),
|
||||||
|
Exp: 3,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
Upper: pgtype.Numeric{
|
||||||
|
Int: big.NewInt(5),
|
||||||
|
Status: pgtype.Present,
|
||||||
|
Exp: 3,
|
||||||
|
},
|
||||||
|
LowerType: pgtype.Inclusive,
|
||||||
|
UpperType: pgtype.Exclusive,
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue