From fa5eae60d2806ecbd94fd10d9e36eaba69b317ee Mon Sep 17 00:00:00 2001 From: Albert Skalt Date: Mon, 31 Jul 2023 23:37:09 +0300 Subject: [PATCH] go-tupleconv: add documentation --- README.md | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 12e4b7b..aea11d4 100644 --- a/README.md +++ b/README.md @@ -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 + +// Function based converter. +fMapper := tupleconv.MakeFuncConverter(func(s string) (string, error) { + return s + " world!", nil +}) +result, err = fMapper.Convert("hello") // hello world! +``` +**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} + +result, err = mapper.MapWithErrHandler([]string{"a", "b"}, func(i int, err error) (any, error) { + return "null", nil +}) // []any{"a1", "null"} +``` +```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", "\n"] +``` +**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"] +``` +**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" +} +```