Skip to content

Commit

Permalink
go-tupleconv: add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
askalt committed Aug 3, 2023
1 parent 3f55d7a commit fa5eae6
Showing 1 changed file with 178 additions and 1 deletion.
179 changes: 178 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,178 @@
# Parser in Go for Tarantool types
# Tarantool tuples converter in Go
## Table of contents
* [Documentation](#documentation)
* [Converter](#converter)
* [Mapper](#mapper)
* [Mappers to tarantool types](#mappers-to-tarantool-types)
* [Example](#example)
* [String to nullable](#string-to-nullable)
* [String to any/scalar](#string-to-anyscalar)
* [Customization](#customization)
## Documentation

### Converter
`Converter[S,T]` converts objects of type `S` into objects of type `T`. Converters
are basic entities on which mappers are based.
Implementations of some converters are available, for example, converters
from strings to golang types.
Usage example:
```golang
// Basic converter.
conv := tupleconv.MakeStringToBoolConverter()
result, err := conv.Convert("true") // true <nil>

// Function based converter.
fMapper := tupleconv.MakeFuncConverter(func(s string) (string, error) {
return s + " world!", nil
})
result, err = fMapper.Convert("hello") // hello world! <nil>
```
**Observation 1**: You can use the provided converters for type conversion,
please make sure to specify the input format they expect before using them.
Examples of supported formats are described in the [tests](converter_test.go).

**Observation 2**: You can create your own converters based on the functions
with `tupleconv.MakeFuncConverter`.

**Observation 3**: You can create your own converters, implementing
`Converter[S,T]` interface.

### Mapper
`Mapper` is an object that converts tuples. It is built using a list of
converters.
Usage example:
```golang
// Mapper example.
mapper := tupleconv.NewMapper[string, any]([]tupleconv.Converter[string, any]{
tupleconv.MakeFuncConverter(func(s string) (any, error) {
return s + "1", nil
}),
tupleconv.MakeFuncConverter(func(s string) (any, error) {
iVal, err := strconv.Atoi(s)
if err != nil {
return nil, errors.New("can't convert")
}
return iVal + 1, nil
}),
})
result, err := mapper.Map([]string{"a", "4"}) // []any{"a1", 5} <nil>

result, err = mapper.MapWithErrHandler([]string{"a", "b"}, func(i int, err error) (any, error) {
return "null", nil
}) // []any{"a1", "null"} <nil>
```
```golang
// Single mapper example.
toStringMapper := tupleconv.NewSingleMapper[any, string](tupleconv.MakeFuncConverter(
func(s any) (string, error) {
return fmt.Sprintln(s), nil
}),
)
res, err := toStringMapper.Map([]any{1, 2.5, nil}) // ["1\n", "2.5\n", "<nil>\n"] <nil>
```
**Observation 1**: To create a mapper, an array of converters is needed, each
of which transforms a certain type S into type T.

**Observation 2**: To perform tuple mapping, you can use the function
`Map`, which will return control to the calling code upon the first error.

**Observation 3**: To perform tuple conversion, you can use the function
`MapWithErrHandler`. Upon a conversion error, it will call the function
provided as the second argument, referred to as the Error Handler.
It will pass the index where the error occurred and the error itself to the
Error Handler. The Error Handler can return a new value for that index or
return an error again to halt the execution of the function at that point.

**Observation 4**: You can use a single converter to create a mapper.
This mapper is created by the function `NewSingleMapper`, and its
`Map` function will work like a `map` function in functional languages.

### Mappers to tarantool types

#### Example
For building an array of converters, especially when it comes to conversions to
tarantool types, there is a built-in solution.
Let's consider an example:
```golang
factory := tupleconv.NewStringToTTConvFactory().
WithDecimalSeparators(",.")

spaceFmt := []tarantool.Field{
{Type: "unsigned"},
{Type: "double", IsNullable: true},
{Type: "string"},
}

converters, _ := tupleconv.MakeTypeToTTConverters[string](factory, spaceFmt)
mapper := tupleconv.NewMapper(converters)
result, err := mapper.Map([]string{"1", "-2,2", "some_string"}) // [1, -2.2, "some_string"] <nil>
```
**Observation 1**: To build an array of converters, the space format and a
certain object implementing `TypeToTTConvFactory` are used. Function
`MakeTypeToTTConverters` takes these entities and gives the converters list.

**Observation 2**: `TypeToTTConvFactory[Type]` is capable of building a
converter from `Type` to each tarantool type.

**Observation 3**: There is a basic factory available called
`StringToTTConvFactory`, which is used for conversions from strings to
tarantool types.

**Observation 4**: `StringToTTMapperFactory` can be configured with options like
`WithDecimalSeparators`.

#### String to nullable
When converting nullable types with `StringToTTConvFactory`, first, an attempt
is made to convert to null.

For example, empty string is interpreted like `null` with default options.
If a field has a `string` type and is `nullable`, then an empty string will be
converted to null during the conversion process, rather than being
converted to empty string.


#### String to any/scalar
When converting to `any`/`scalar` with `StringToTTConvFactory`, by default,
an attempt will be made to convert them to the following types,
in the following order:
- `number`
- `decimal`
- `boolean`
- `datetime`
- `uuid`
- `interval`
- `string`

#### Customization
`TypeToTTConvFactory[Type]` is an interface that can build a mapper from
`Type` to each tarantool type.
To customize the behavior for specific types, one can
inherit from the existing factory and override the necessary methods.
For example, let's make the standard factory for conversion from strings to
tarantool types always convert `any` type to a string:
```golang
package main

import (
"github.com/tarantool/go-tarantool/v2"
"github.com/tarantool/go-tupleconv"
)

type customFacture struct {
tupleconv.StringToTTConvFactory
}

func (f *customFacture) MakeTypeToAnyMapper() tupleconv.Converter[string, any] {
return tupleconv.MakeFuncConverter(func(s string) (any, error) {
return s, nil
})
}

func main() {
facture := &customFacture{}
spaceFmt := []tarantool.Field{{Type: "any"}}
converters, _ := tupleconv.MakeTypeToTTConverters[string](facture, spaceFmt)

res, err := converters[0].Convert("12") // "12" <nil>
}
```

0 comments on commit fa5eae6

Please sign in to comment.