diff --git a/README.md b/README.md index 12e4b7b..51e914a 100644 --- a/README.md +++ b/README.md @@ -1 +1,185 @@ -# Parser in Go for Tarantool types +# Tarantool tuples converter in Go +## Table of contents +* [Documentation](#documentation) + * [Mapper](#mapper) + * [Converter](#converter) + * [Convert to tarantool types](#convert-to-tarantool-types) + * [Example](#example) + * [String to nullable](#string-to-nullable) + * [String to any/scalar](#string-to-anyscalar) + * [Customization](#customization) +## Documentation + +### Mapper +`Mapper[S,T]` maps objects of type `S` into objects of type `T`. Mappers are +basic entities on which converters are based. +Implementations of some mappers are available, for example, mappers from strings +to go types. +Usage example: +```golang +// Basic mapper. +mapper := tupleconv.MakeStringToBoolMapper() +result, err := mapper.Map("true") // true + +// Function based mapper. +fMapper := tupleconv.MakeFuncMapper(func(s string) (string, error) { + return s + " world!", nil +}) +result, err = fMapper.Map("hello") // hello world! +``` +**Observation 1**: You can use the provided mappers 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](mapper_test.go). + +**Observation 2**: You can create your own mappers based on the functions with +`tupleconv.MakeFuncMapper`. + +**Observation 3**: You can create your own mappers, implementing `Mapper[S,T]` +interface. + +### Converter +`Converter` is an object that converts tuples. It is built using a list of +mappers. +Usage example: +```golang +// Converter example. +customConverter := tupleconv.NewConverter[string, any]([]tupleconv.Mapper[string, any]{ + tupleconv.MakeFuncMapper(func(s string) (any, error) { + return s + "1", nil + }), + tupleconv.MakeFuncMapper(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 := customConverter.Convert([]string{"a", "4"}) // []any{"a1", 5} + +result, err = customConverter.ConvertWithErrHandler([]string{"a", "b"}, func(i int, err error) (any, error) { + return "null", nil +}) // []any{"a1", "null"} +``` +```golang +// Single converter example. +toStringConverter := tupleconv.NewConverterSingle[any, string](tupleconv.MakeFuncMapper( + func(s any) (string, error) { + return fmt.Sprintln(s), nil + }), +) +res, err := toStringConverter.Convert([]any{1, 2.5, nil}) // ["1\n", "2.5\n", "\n"] +``` +**Observation 1**: To create a converter, an array of mappers is needed, each +of which transforms a certain type S into type T. + +**Observation 2**: To perform tuple conversion, you can use the function +`Convert`, which will return control to the calling code upon the first error. + +**Observation 3**: To perform tuple conversion, you can use the function +`ConvertWithErrHandler`. 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 mapper to create a converter. +This converter is created by the function `NewConverterSingle`, and its +`Convert` function will work like a `map` function in some programming languages. + +### Convert to tarantool types + +#### Example +For building an array of mappers, especially when it comes to conversions to +Tarantool types, there is a built-in solution. +Let's consider an example: +```golang +package main + +import "github.com/tarantool/go-tupleconv" + +func main() { + factory := tupleconv.NewStringToTTMapperFactory() + factory.Cfg(tupleconv.StringToTTMapperOpts{ + DecSeparators: ",.", + }) + + spaceFmt := []tarantool.Field{ + {Type: "unsigned"}, + {Type: "double", IsNullable: true}, + {Type: "string"}, + } + + mappers, err := tupleconv.MakeTypeToTTMapperList[string](factory, spaceFmt) + converter := tupleconv.NewConverter(mappers) + converter.Convert([]string{"1", "-2,2", "some_string"}) // [1, -2.2, "some_string"] +} +``` +**Observation 1**: To build an array of mappers, the space format and a certain +object called `TypeToTTMapperFactory` are used. Function +`MakeTypeToTTMapperList` takes these entities and gives the mappers list. + +**Observation 2**: `TypeToTTMapperFactory[Type]` is capable of building a mapper +from type `Type` to each Tarantool type. + +**Observation 3**: There is a basic factory available called +`StringToTTMapperFactory`, which is used for conversions from strings to +Tarantool types. + +**Observation 4**: `StringToTTMapperFactory` can be configured with `Cfg`. + +#### String to nullable +When converting nullable types with `StringToTTMapperFactory`, an attempt will +be made to convert them to the base type. + +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 an empty string during the conversion process, rather than being +converted to null. + + +#### String to any/scalar +When converting to `any`/`scalar` with `StringToTTMapperFactory`, 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 +`TypeToTTMapperFactory[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 mappers 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.StringToTTMapperFactory +} + +func (f *customFacture) MakeTypeToAnyMapper() tupleconv.Mapper[string, any] { + return tupleconv.MakeFuncMapper(func(s string) (any, error) { + return s, nil + }) +} + +func main() { + facture := &customFacture{} + spaceFmt := []tarantool.Field{{Type: "any"}} + mappers, _ := tupleconv.MakeTypeToTTMapperList[string](facture, spaceFmt) + + res, err := mappers[0].Map("12") // "12" +} +```