Skip to content

Commit

Permalink
tupleconv: add tt interval type.
Browse files Browse the repository at this point in the history
Added support for the tarantool `interval` type:

- implemented a parser for this format. Currently, the supported format is
the order of interval fields  from most significant to least significant, as follows:
`year,month,week,day,hour,min,sec,nsec,adjust`.

- added the `interval` type to the table of tarantool types, and now the parsing
of interval is used for parsing `any` and `scalar` types.
  • Loading branch information
askalt committed Jul 28, 2023
1 parent bfd5b9d commit f59721d
Show file tree
Hide file tree
Showing 5 changed files with 122 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/datetime"
Expand Down Expand Up @@ -30,6 +31,7 @@ var (
_ Mapper[string, any] = (*SliceParser)(nil)
_ Mapper[string, any] = (*BinaryParser)(nil)
_ Mapper[string, any] = (*NullParser)(nil)
_ Mapper[string, any] = (*IntervalParser)(nil)
)

// FuncMapper is a function-based Mapper.
Expand Down Expand Up @@ -264,3 +266,48 @@ func (parser NullParser) Map(src string) (any, error) {
}
return nil, nil
}

// IntervalParser is a parser to datetime.Interval.
type IntervalParser struct{}

// NewIntervalParser creates IntervalParser.
func NewIntervalParser() IntervalParser {
return IntervalParser{}
}

// 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 IntervalParser.
func (IntervalParser) 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 @@ -223,6 +223,27 @@ func TestParsers(t *testing.T) {
{value: "505", isErr: true},
{value: "nil", isErr: true},
},
tupleconv.NewIntervalParser(): {
// 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
4 changes: 4 additions & 0 deletions tt.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var parserByTTType = map[TypeName]Mapper[string, any]{
NewDecimalParser(defaultIgnoreChars, defaultDecSeparators),
NewBoolParser(),
NewDateTimeParser(),
NewIntervalParser(),
NewUUIDParser(),
NewStringParser(), // Always success.
}),
Expand All @@ -60,9 +61,12 @@ var parserByTTType = map[TypeName]Mapper[string, any]{
NewDecimalParser(defaultIgnoreChars, defaultDecSeparators),
NewBoolParser(),
NewDateTimeParser(),
NewIntervalParser(),
NewUUIDParser(),
NewStringParser(), // Always success.
}),

TypeInterval: NewIntervalParser(),
}

// NewParserFor returns parser by the type name and `isNullable` property.
Expand Down
49 changes: 49 additions & 0 deletions tt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ func TestNewParserFor(t *testing.T) {
{value: "", isNullable: true, expected: ""},
{value: "09b56913-11f0-4fa4-b5d0-901b5efa532a", expected: someUUID},
{value: "2020-08-22T11:27:43.123456789-02:00", expected: dateTime1},
{
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: {
Expand All @@ -240,6 +252,43 @@ func TestNewParserFor(t *testing.T) {
{value: "", isNullable: true, expected: ""},
{value: "09b56913-11f0-4fa4-b5d0-901b5efa532a", expected: someUUID},
{value: "2020-08-22T11:27:43.123456789-02:00", expected: dateTime1},
{
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.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},
},
}

Expand Down
1 change: 1 addition & 0 deletions tt_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ const (
TypeVarbinary TypeName = "varbinary"
TypeScalar TypeName = "scalar"
TypeAny TypeName = "any"
TypeInterval TypeName = "interval"
)

0 comments on commit f59721d

Please sign in to comment.