diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cb2f6d2c..63d86be37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* Added support for nullable `Date32`, `Datetime64`, `Timestamp64`, and `Interval64` types in the `optional` parameter builder * Fixed race in `readerReconnector` ## v3.117.1 diff --git a/internal/params/optional.go b/internal/params/optional.go index 665bc318b..62cc4da10 100644 --- a/internal/params/optional.go +++ b/internal/params/optional.go @@ -119,24 +119,48 @@ func (p *optional) Timestamp(v *time.Time) *optionalBuilder { return &optionalBuilder{opt: p} } +func (p *optional) Timestamp64(v *time.Time) *optionalBuilder { + p.value = value.NullableTimestamp64ValueFromTime(v) + + return &optionalBuilder{opt: p} +} + func (p *optional) Date(v *time.Time) *optionalBuilder { p.value = value.NullableDateValueFromTime(v) return &optionalBuilder{opt: p} } +func (p *optional) Date32(v *time.Time) *optionalBuilder { + p.value = value.NullableDate32ValueFromTime(v) + + return &optionalBuilder{opt: p} +} + func (p *optional) Datetime(v *time.Time) *optionalBuilder { p.value = value.NullableDatetimeValueFromTime(v) return &optionalBuilder{opt: p} } +func (p *optional) Datetime64(v *time.Time) *optionalBuilder { + p.value = value.NullableDatetime64ValueFromTime(v) + + return &optionalBuilder{opt: p} +} + func (p *optional) Interval(v *time.Duration) *optionalBuilder { p.value = value.NullableIntervalValueFromDuration(v) return &optionalBuilder{opt: p} } +func (p *optional) Interval64(v *time.Duration) *optionalBuilder { + p.value = value.NullableInterval64ValueFromDuration(v) + + return &optionalBuilder{opt: p} +} + func (p *optional) JSON(v *string) *optionalBuilder { p.value = value.NullableJSONValue(v) diff --git a/internal/params/optional_test.go b/internal/params/optional_test.go index ee6cf4d4e..5c7ec4cc9 100644 --- a/internal/params/optional_test.go +++ b/internal/params/optional_test.go @@ -317,6 +317,26 @@ func TestOptional(t *testing.T) { }, }, }, + { + method: "Interval64", + args: []any{p(time.Duration(123456789))}, + expected: expected{ + Type: &Ydb.Type{ + Type: &Ydb.Type_OptionalType{ + OptionalType: &Ydb.OptionalType{ + Item: &Ydb.Type{ + Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL64}, + }, + }, + }, + }, + Value: &Ydb.Value{ + Value: &Ydb.Value_Int64Value{ + Int64Value: 123456789, // nanoseconds + }, + }, + }, + }, { method: "Datetime", args: []any{p(time.Unix(123456789, 456))}, @@ -338,6 +358,26 @@ func TestOptional(t *testing.T) { }, }, }, + { + method: "Datetime64", + args: []any{p(time.Unix(123456789, 456))}, + expected: expected{ + Type: &Ydb.Type{ + Type: &Ydb.Type_OptionalType{ + OptionalType: &Ydb.OptionalType{ + Item: &Ydb.Type{ + Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME64}, + }, + }, + }, + }, + Value: &Ydb.Value{ + Value: &Ydb.Value_Int64Value{ + Int64Value: 123456789, + }, + }, + }, + }, { method: "Date", args: []any{p(time.Unix(123456789, 456))}, @@ -359,6 +399,26 @@ func TestOptional(t *testing.T) { }, }, }, + { + method: "Date32", + args: []any{p(time.Unix(123456789, 456))}, + expected: expected{ + Type: &Ydb.Type{ + Type: &Ydb.Type_OptionalType{ + OptionalType: &Ydb.OptionalType{ + Item: &Ydb.Type{ + Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE32}, + }, + }, + }, + }, + Value: &Ydb.Value{ + Value: &Ydb.Value_Int32Value{ + Int32Value: 1428, + }, + }, + }, + }, { method: "Timestamp", args: []any{p(time.Unix(123456789, 456))}, @@ -380,6 +440,26 @@ func TestOptional(t *testing.T) { }, }, }, + { + method: "Timestamp64", + args: []any{p(time.Unix(123456789, 123456000))}, + expected: expected{ + Type: &Ydb.Type{ + Type: &Ydb.Type_OptionalType{ + OptionalType: &Ydb.OptionalType{ + Item: &Ydb.Type{ + Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP64}, + }, + }, + }, + }, + Value: &Ydb.Value{ + Value: &Ydb.Value_Int64Value{ + Int64Value: 123456789123456, // microseconds + }, + }, + }, + }, { method: "Decimal", args: []any{p([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}), uint32(22), uint32(9)}, diff --git a/internal/value/nullable.go b/internal/value/nullable.go index ef5c9fba1..0d9fb6f91 100644 --- a/internal/value/nullable.go +++ b/internal/value/nullable.go @@ -143,6 +143,22 @@ func NullableDateValueFromTime(v *time.Time) Value { return OptionalValue(DateValueFromTime(*v)) } +func NullableDate32Value(v *int32) Value { + if v == nil { + return NullValue(types.Date32) + } + + return OptionalValue(Date32Value(*v)) +} + +func NullableDate32ValueFromTime(v *time.Time) Value { + if v == nil { + return NullValue(types.Date32) + } + + return OptionalValue(Date32ValueFromTime(*v)) +} + func NullableDatetimeValue(v *uint32) Value { if v == nil { return NullValue(types.Datetime) @@ -151,6 +167,22 @@ func NullableDatetimeValue(v *uint32) Value { return OptionalValue(DatetimeValue(*v)) } +func NullableDatetime64Value(v *int64) Value { + if v == nil { + return NullValue(types.Datetime64) + } + + return OptionalValue(Datetime64Value(*v)) +} + +func NullableDatetime64ValueFromTime(v *time.Time) Value { + if v == nil { + return NullValue(types.Datetime64) + } + + return OptionalValue(Datetime64ValueFromTime(*v)) +} + func NullableDatetimeValueFromTime(v *time.Time) Value { if v == nil { return NullValue(types.Datetime) @@ -223,6 +255,22 @@ func NullableTimestampValueFromTime(v *time.Time) Value { return OptionalValue(TimestampValueFromTime(*v)) } +func NullableTimestamp64Value(v *int64) Value { + if v == nil { + return NullValue(types.Timestamp64) + } + + return OptionalValue(Timestamp64Value(*v)) +} + +func NullableTimestamp64ValueFromTime(v *time.Time) Value { + if v == nil { + return NullValue(types.Timestamp64) + } + + return OptionalValue(Timestamp64ValueFromTime(*v)) +} + func NullableTzTimestampValue(v *string) Value { if v == nil { return NullValue(types.TzTimestamp) @@ -255,6 +303,22 @@ func NullableIntervalValueFromDuration(v *time.Duration) Value { return OptionalValue(IntervalValueFromDuration(*v)) } +func NullableInterval64ValueFromNanoseconds(v *int64) Value { + if v == nil { + return NullValue(types.Interval64) + } + + return OptionalValue(Interval64Value(*v)) +} + +func NullableInterval64ValueFromDuration(v *time.Duration) Value { + if v == nil { + return NullValue(types.Interval64) + } + + return OptionalValue(Interval64ValueFromDuration(*v)) +} + func NullableBytesValue(v *[]byte) Value { if v == nil { return NullValue(types.Bytes) @@ -451,6 +515,15 @@ func Nullable(t types.Type, v interface{}) Value { default: panic(fmt.Sprintf("unsupported type conversion from %T to TypeDate", tt)) } + case types.Date32: + switch tt := v.(type) { + case *int32: + return NullableDate32Value(tt) + case *time.Time: + return NullableDate32ValueFromTime(tt) + default: + panic(fmt.Sprintf("unsupported type conversion from %T to TypeDate32", tt)) + } case types.Datetime: switch tt := v.(type) { case *uint32: @@ -460,6 +533,15 @@ func Nullable(t types.Type, v interface{}) Value { default: panic(fmt.Sprintf("unsupported type conversion from %T to TypeDatetime", tt)) } + case types.Datetime64: + switch tt := v.(type) { + case *int64: + return NullableDatetime64Value(tt) + case *time.Time: + return NullableDatetime64ValueFromTime(tt) + default: + panic(fmt.Sprintf("unsupported type conversion from %T to TypeDatetime64", tt)) + } case types.Timestamp: switch tt := v.(type) { case *uint64: @@ -469,6 +551,15 @@ func Nullable(t types.Type, v interface{}) Value { default: panic(fmt.Sprintf("unsupported type conversion from %T to TypeTimestamp", tt)) } + case types.Timestamp64: + switch tt := v.(type) { + case *int64: + return NullableTimestamp64Value(tt) + case *time.Time: + return NullableTimestamp64ValueFromTime(tt) + default: + panic(fmt.Sprintf("unsupported type conversion from %T to TypeTimestamp64", tt)) + } case types.Interval: switch tt := v.(type) { case *int64: @@ -478,6 +569,15 @@ func Nullable(t types.Type, v interface{}) Value { default: panic(fmt.Sprintf("unsupported type conversion from %T to TypeInterval", tt)) } + case types.Interval64: + switch tt := v.(type) { + case *int64: + return NullableInterval64ValueFromNanoseconds(tt) + case *time.Duration: + return NullableInterval64ValueFromDuration(tt) + default: + panic(fmt.Sprintf("unsupported type conversion from %T to TypeInterval64", tt)) + } case types.TzDate: switch tt := v.(type) { case *string: diff --git a/table/types/value.go b/table/types/value.go index 5be00d445..591affdbd 100644 --- a/table/types/value.go +++ b/table/types/value.go @@ -38,12 +38,21 @@ func DoubleValue(v float64) Value { return value.DoubleValue(v) } // DateValue returns ydb date value by given days since Epoch func DateValue(v uint32) Value { return value.DateValue(v) } +// Date32Value returns ydb date32 value by given days since Epoch +func Date32Value(v int32) Value { return value.Date32Value(v) } + // DatetimeValue makes ydb datetime value from seconds since Epoch func DatetimeValue(v uint32) Value { return value.DatetimeValue(v) } +// Datetime64Value returns ydb datetime64 value by given seconds since Epoch +func Datetime64Value(v int64) Value { return value.Datetime64Value(v) } + // TimestampValue makes ydb timestamp value from microseconds since Epoch func TimestampValue(v uint64) Value { return value.TimestampValue(v) } +// Timestamp64Value returns ydb timestamp64 value by given microseconds since Epoch (int64) +func Timestamp64Value(v int64) Value { return value.Timestamp64Value(v) } + // IntervalValueFromMicroseconds makes Value from given microseconds value func IntervalValueFromMicroseconds(v int64) Value { return value.IntervalValue(v) } @@ -54,6 +63,9 @@ func IntervalValueFromMicroseconds(v int64) Value { return value.IntervalValue(v // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated func IntervalValue(v int64) Value { return value.IntervalValue(v) } +// Interval64ValueFromNanoseconds returns ydb interval64 value by given nanoseconds +func Interval64ValueFromNanoseconds(v int64) Value { return value.Interval64Value(v) } + // TzDateValue makes TzDate value from string func TzDateValue(v string) Value { return value.TzDateValue(v) } @@ -334,6 +346,14 @@ func NullableDateValueFromTime(v *time.Time) Value { return value.NullableDateValueFromTime(v) } +func NullableDate32Value(v *int32) Value { + return value.NullableDate32Value(v) +} + +func NullableDate32ValueFromTime(v *time.Time) Value { + return value.NullableDate32ValueFromTime(v) +} + func NullableDecimalValue(v *[16]byte, precision, scale uint32) Value { return value.NullableDecimalValue(v, precision, scale) } @@ -350,6 +370,14 @@ func NullableDatetimeValueFromTime(v *time.Time) Value { return value.NullableDatetimeValueFromTime(v) } +func NullableDatetime64Value(v *int64) Value { + return value.NullableDatetime64Value(v) +} + +func NullableDatetime64ValueFromTime(v *time.Time) Value { + return value.NullableDatetime64ValueFromTime(v) +} + func NullableTzDateValue(v *string) Value { return value.NullableTzDateValue(v) } @@ -374,6 +402,14 @@ func NullableTimestampValueFromTime(v *time.Time) Value { return value.NullableTimestampValueFromTime(v) } +func NullableTimestamp64Value(v *int64) Value { + return value.NullableTimestamp64Value(v) +} + +func NullableTimestamp64ValueFromTime(v *time.Time) Value { + return value.NullableTimestamp64ValueFromTime(v) +} + func NullableTzTimestampValue(v *string) Value { return value.NullableTzTimestampValue(v) } @@ -399,6 +435,14 @@ func NullableIntervalValueFromDuration(v *time.Duration) Value { return value.NullableIntervalValueFromDuration(v) } +func NullableInterval64ValueFromNanoseconds(v *int64) Value { + return value.NullableInterval64ValueFromNanoseconds(v) +} + +func NullableInterval64ValueFromDuration(v *time.Duration) Value { + return value.NullableInterval64ValueFromDuration(v) +} + // NullableStringValue // // Deprecated: use NullableBytesValue instead.