Skip to content

Commit

Permalink
tupleconv: add tt interval type
Browse files Browse the repository at this point in the history
  • Loading branch information
askalt committed Aug 1, 2023
1 parent 93e02da commit 31bca4b
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
47 changes: 47 additions & 0 deletions mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tupleconv

import (
"encoding/json"
"errors"
"fmt"
"github.com/google/uuid"
"github.com/tarantool/go-tarantool/v2/datetime"
Expand Down Expand Up @@ -30,6 +31,7 @@ var (
_ Mapper[string, any] = (*StringToSliceMapper)(nil)
_ Mapper[string, any] = (*StringToNullMapper)(nil)
_ Mapper[string, any] = (*IdentityMapper[string])(nil)
_ Mapper[string, any] = (*StringToIntervalMapper)(nil)
)

// IdentityMapper is a mapper from S to any, that doesn't change the input.
Expand Down Expand Up @@ -260,3 +262,48 @@ func (mapper StringToNullMapper) Map(src string) (any, error) {
}
return nil, nil
}

// StringToIntervalMapper is a mapper from string to datetime.Interval.
type StringToIntervalMapper struct{}

// MakeStringToIntervalMapper creates StringToIntervalMapper.
func MakeStringToIntervalMapper() StringToIntervalMapper {
return StringToIntervalMapper{}
}

// intervalFieldsNumber is the number of fields in datetime.Interval.
const intervalFieldsNumber = 9

var errUnexpectedIntervalFmt = errors.New("unexpected interval format")

// Map is the implementation of Mapper[string] for StringToIntervalMapper.
func (StringToIntervalMapper) Map(src string) (any, error) {
parts := strings.Split(src, ",")
if len(parts) != intervalFieldsNumber {
return nil, errUnexpectedIntervalFmt
}
partsAsInt64 := [intervalFieldsNumber]int64{}
for i, part := range parts {
var err error
if partsAsInt64[i], err = strconv.ParseInt(part, 10, 64); err != nil {
return nil, errUnexpectedIntervalFmt
}
}
adjust := datetime.Adjust(partsAsInt64[8])
if adjust != datetime.NoneAdjust &&
adjust != datetime.ExcessAdjust && adjust != datetime.LastAdjust {
return nil, errUnexpectedIntervalFmt
}
interval := datetime.Interval{
Year: partsAsInt64[0],
Month: partsAsInt64[1],
Week: partsAsInt64[2],
Day: partsAsInt64[3],
Hour: partsAsInt64[4],
Min: partsAsInt64[5],
Sec: partsAsInt64[6],
Nsec: partsAsInt64[7],
Adjust: adjust,
}
return interval, nil
}
21 changes: 21 additions & 0 deletions mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,27 @@ func TestParsers(t *testing.T) {
{value: "-1/0", isErr: true},
{value: "1**5", isErr: true},
},
tupleconv.MakeStringToIntervalMapper(): {
// Basic.
{
value: "1,2,3,4,5,6,7,8,1",
expected: datetime.Interval{
Year: 1, Month: 2, Week: 3, Day: 4, Hour: 5, Min: 6, Sec: 7, Nsec: 8, Adjust: 1,
},
},
{
value: "-11,-1110,0,0,0,0,0,1,2",
expected: datetime.Interval{
Year: -11, Month: -1110, Nsec: 1, Adjust: 2,
},
},

// Error.
{value: "1,2,3,4,5,6,7,8,3", isErr: true}, // Invalid adjust.
{value: "1,2,3", isErr: true},
{value: "1,2,3,4,5,6,7a,8,0", isErr: true},
{value: "", isErr: true},
},
}

for parser, cases := range tests {
Expand Down
12 changes: 12 additions & 0 deletions tt.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
TypeVarbinary TypeName = "varbinary"
TypeScalar TypeName = "scalar"
TypeAny TypeName = "any"
TypeInterval TypeName = "interval"
)

const (
Expand Down Expand Up @@ -76,6 +77,9 @@ type TypeToTTMapperFactory[Type any] interface {
// MakeTypeToScalarMapper creates a mapper from Type to scalar.
MakeTypeToScalarMapper() Mapper[Type, any]

// MakeTypeToIntervalMapper creates a mapper from Type to interval.
MakeTypeToIntervalMapper() Mapper[Type, any]

// MakeNullableMapper extends the incoming mapper to a nullable mapper.
MakeNullableMapper(Mapper[Type, any]) Mapper[Type, any]
}
Expand Down Expand Up @@ -184,6 +188,7 @@ func (fac *StringToTTMapperFactory) MakeTypeToAnyMapper() Mapper[string, any] {
fac.MakeTypeToBooleanMapper(),
fac.MakeTypeToDatetimeMapper(),
fac.MakeTypeToUUIDMapper(),
fac.MakeTypeToIntervalMapper(),
fac.MakeTypeToStringMapper(),
})
}
Expand All @@ -195,6 +200,7 @@ func (fac *StringToTTMapperFactory) MakeTypeToScalarMapper() Mapper[string, any]
fac.MakeTypeToBooleanMapper(),
fac.MakeTypeToDatetimeMapper(),
fac.MakeTypeToUUIDMapper(),
fac.MakeTypeToIntervalMapper(),
fac.MakeTypeToStringMapper(),
})
}
Expand All @@ -207,6 +213,10 @@ func (fac *StringToTTMapperFactory) MakeNullableMapper(
})
}

func (fac *StringToTTMapperFactory) MakeTypeToIntervalMapper() Mapper[string, any] {
return MakeStringToIntervalMapper()
}

// Cfg configures StringToTTMapperFactory with the provided options.
func (fac *StringToTTMapperFactory) Cfg(opts StringToTTMapperOpts) {
fac.opts = opts
Expand Down Expand Up @@ -251,6 +261,8 @@ func MakeTypeToTTMapperList[Type any](
mappers[i] = fac.MakeTypeToAnyMapper()
case TypeScalar:
mappers[i] = fac.MakeTypeToScalarMapper()
case TypeInterval:
mappers[i] = fac.MakeTypeToIntervalMapper()
default:
return nil, fmt.Errorf("unexpected type: %s", typ)
}
Expand Down
73 changes: 73 additions & 0 deletions tt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,18 @@ func TestMakeStringTOTTMapperList_defaultFactory(t *testing.T) {
{value: "09b56913-11f0-4fa4-b5d0-901b5efa532a", expected: someUUID},
{value: "2020-08-22T11:27:43.123456789-02:00", expected: dateTime1},
{value: "1`e2", expected: "1`e2"},
{
value: "1,2,3,4,5,6,7,8,1",
expected: datetime.Interval{
Year: 1, Month: 2, Week: 3, Day: 4, Hour: 5, Min: 6, Sec: 7, Nsec: 8, Adjust: 1,
},
},
{
value: "-11,-1110,0,0,0,0,0,1,2",
expected: datetime.Interval{
Year: -11, Month: -1110, Nsec: 1, Adjust: 2,
},
},
},
tupleconv.TypeScalar: {
{value: "blablabla", expected: "blablabla"},
Expand All @@ -310,6 +322,18 @@ func TestMakeStringTOTTMapperList_defaultFactory(t *testing.T) {
{value: "09b56913-11f0-4fa4-b5d0-901b5efa532a", expected: someUUID},
{value: "2020-08-22T11:27:43.123456789-02:00", expected: dateTime1},
{value: "1`e2", expected: "1`e2"},
{
value: "1,2,3,4,5,6,7,8,1",
expected: datetime.Interval{
Year: 1, Month: 2, Week: 3, Day: 4, Hour: 5, Min: 6, Sec: 7, Nsec: 8, Adjust: 1,
},
},
{
value: "-11,-1110,0,0,0,0,0,1,2",
expected: datetime.Interval{
Year: -11, Month: -1110, Nsec: 1, Adjust: 2,
},
},
},

tupleconv.TypeDecimal: {
Expand Down Expand Up @@ -350,6 +374,30 @@ func TestMakeStringTOTTMapperList_defaultFactory(t *testing.T) {
{value: "-1/0", isErr: true},
{value: "1**5", isErr: true},
},
tupleconv.TypeInterval: {
// Basic.
{
value: "1,2,3,4,5,6,7,8,1",
expected: datetime.Interval{
Year: 1, Month: 2, Week: 3, Day: 4, Hour: 5, Min: 6, Sec: 7, Nsec: 8, Adjust: 1,
},
},
{
value: "-11,-1110,0,0,0,0,0,1,2",
expected: datetime.Interval{
Year: -11, Month: -1110, Nsec: 1, Adjust: 2,
},
},

// Nullable.
{value: "", isNullable: true, expected: nil},

// Error.
{value: "1,2,3,4,5,6,7,8,3", isErr: true}, // Invalid adjust.
{value: "1,2,3", isErr: true},
{value: "1,2,3,4,5,6,7a,8,0", isErr: true},
{value: "", isErr: true},
},
}

fac := tupleconv.NewStringToTTMapperFactory()
Expand Down Expand Up @@ -589,6 +637,31 @@ func TestMakeStringTOTTMapperList_configuredFactory(t *testing.T) {
{value: "1,,2", isErr: true},
{value: "hello", isErr: true},
},
tupleconv.TypeInterval: {
// Basic.
{
value: "1,2,3,4,5,6,7,8,1",
expected: datetime.Interval{
Year: 1, Month: 2, Week: 3, Day: 4, Hour: 5, Min: 6, Sec: 7, Nsec: 8, Adjust: 1,
},
},
{
value: "-11,-1110,0,0,0,0,0,1,2",
expected: datetime.Interval{
Year: -11, Month: -1110, Nsec: 1, Adjust: 2,
},
},

// Nullable.
{value: "null", isNullable: true, expected: nil},
{value: "", isNullable: true, isErr: true},

// Error.
{value: "1#2#3#4#5#6#7#8#3", isErr: true}, // Invalid adjust.
{value: "1,2,3", isErr: true},
{value: "1,2,3,4,5,6,7a,8,0", isErr: true},
{value: "", isErr: true},
},
}

opts := tupleconv.StringToTTMapperOpts{
Expand Down

0 comments on commit 31bca4b

Please sign in to comment.