tuples

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2022 License: MIT Imports: 11 Imported by: 0

README

tuples

codecov

Go package tuples reads and writes tuples string - a string containing a list of records/tuples separated by a delimiter.

It's not rare when a configuration parameter represents a record or a list of records. For example:

SUPPORTED_FORMATS="height=700,width=350,format=jpeg height=900,width=450,format=png"

The tuples package allows to unmarshal such strings to a predefined Go structure or an arbitrary map. It also supports structure and map marshaling to a tuples string.

Installation

go get github.com/antklim/tuples

Format

The tuples string format is the following:

<name=value>,... [<name=value>,...]

There are three delimiters in format:

  • key-value delimiter, the default value is =
  • filds delimiter, the default value is ,
  • tuples (records) delimiter, the default value is (a whitespace)

A string can contain 0 to N tuples. Each tuple can consist of 1 to M fields.

Usage

Unmarshal

The package uses tuples tag followed by the field name to decode to a Go structure. Structure fields without the tuples tag omitted during decoding. The following field types are supported: int*, uint*, float*, string, and bool. Decoding to unsupported field type will cause an UnmarshalUnsupportedTypeError.

When unmarshaling to a map the tuples string field names become keys in the map.

The package does not read the full tuples string for decoding. It scans the string tuple by tuple. It is not possible to know ahead how many tuples the string contains. Therefore, the package only accepts the following unmarshaling destinations:

  • a slice or array of a struct
  • an interface.

In case when an interface (any) provided as the decoding destination, a slice of the arbitrary maps produced: []map[string]any. Note, map keys will be alphabetically sorted.

package main

import(
	"fmt"

	"github.com/antklim/tuples"
)

type format struct {
	Height int    `tuples:"h"`
	Width  int    `tuples:"w"`
	Format string `tuples:"f"`
}

func main() {
	formatsConf := "h=700,w=350,f=jpeg h=900,w=450,f=png"

	var formats []format
	if err := tuples.Unmarshal([]byte(formatsConf), &formats); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%+v\n", formats)

	var anys any
	if err := tuples.Unmarshal([]byte("b=2,a=1 d=4,c=3"), &anys); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%+v\n", anys)

	// Output:
	// [{Height:700 Width:350 Format:jpeg} {Height:900 Width:450 Format:png}]
	// [map[a:1 b:2] map[c:3 d:4]]
}

Additionally, the package provides a Reader. It reads a tuples string and produces a collection of tuple values. You can read all tuples at once, as in the following example.

package main

import(
	"fmt"
	"strings"

	"github.com/antklim/tuples"
)

func main() {
	formatsConf := "h=700,w=350,f=jpeg h=900,w=450,f=png"

	r, err := tuples.NewReader(strings.NewReader(formatsConf))
	if err != nil {
		fmt.Println(err)
	}

	v, err := r.ReadAll()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%v\n", v)

	// Output:
	// [[700 350 jpeg] [900 450 png]]
}

Or read tuple by tuple.

package main

import(
	"fmt"
	"strings"

	"github.com/antklim/tuples"
)

func main() {
	formatsConf := "h=700,w=350,f=jpeg h=900,w=450,f=png"

	r, err := tuples.NewReader(strings.NewReader(formatsConf))
	if err != nil {
		fmt.Println(err)
	}

	for {
		tuple, err := r.Read()
		if err == io.EOF {
			break
		}

		if err != nil {
			fmt.Println(err)
		}
		fmt.Printf("%v\n", tuple)
	}

	// Output:
	// [700 350 jpeg]
 	// [900 450 png]
}

Marshal

The package uses only the fields with the tag tuples when marshaling Go structures. The tag value used as a field name in the resulting tuples string.

When marshaling a map the package uses the map key as the field names in the resulting tuples string.

package main

import(
	"fmt"
	"strings"

	"github.com/antklim/tuples"
)

func main() {
	type person struct {
		Name string `tuples:"full_name"`
		Age  int    `tuples:"years-old"`
	}

	p := person{Name: "Bob", Age: 33}

	b, err := tuples.Marshal(p)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%s\n", string(b))

	// Output:
	// full_name=Bob,years-old=33
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Marshal

func Marshal(v any) ([]byte, error)

Marshal returns tuples encoding of v.

Marshal supports:

  • struct with tags
  • pointer to a struct with tags
  • slice of structs with tags
  • pointer to slice of structs with tags
  • map
  • pointer to a map
  • slice of maps
  • pointer to a slice of maps

In case of map, map key value used as tuple key. All map entries marshaled.

Only basic types supported as values, i.e string, int, float, boolean. MarshalError returned in case, when unsupported type found.

Example
package main

import (
	"fmt"

	"github.com/antklim/tuples"
)

func main() {
	type person struct {
		Name string `tuples:"full_name"`
		Age  int    `tuples:"years-old"`
	}

	p := person{Name: "Bob", Age: 33}

	b, err := tuples.Marshal(p)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%s\n", string(b))

	pp := []person{{Name: "Bob", Age: 33}, {Name: "Paul", Age: 99}}

	b, err = tuples.Marshal(pp)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%s\n", string(b))

}
Output:

full_name=Bob,years-old=33
full_name=Bob,years-old=33 full_name=Paul,years-old=99

func ReadString

func ReadString(s string, opts ...ReaderOption) ([][]string, error)

ReadString reads all tuples from the string. It returns a slice of tuples values. It returns error when reader initialisation failed or read process failed.

Usage:

tuples, err := ReadString("fname=John,lname=Doe dob=2000-01-01 age=17")
if err != nil {
	return err
}
fmt.Println(tuples)

// Output:
// [[John Doe] [2000-01-01] [17]]
Example
package main

import (
	"fmt"

	"github.com/antklim/tuples"
)

func main() {
	in := "fname=John,lname=Doe,dob=2000-01-01 fname=Bob,lname=Smith,dob=2010-10-10"

	v, err := tuples.ReadString(in)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%v\n", v)

}
Output:

[[John Doe 2000-01-01] [Bob Smith 2010-10-10]]

func Unmarshal

func Unmarshal(data []byte, v any) error

Unmarshal parses the tuples-encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

Example
package main

import (
	"fmt"

	"github.com/antklim/tuples"
)

func main() {
	type person struct {
		Name    string `tuples:"name"`
		Age     int    `tuples:"age"`
		IsAdult bool   `tuples:"adult"`
	}

	in := "name=John,age=23,adult=true"
	var p []person
	if err := tuples.Unmarshal([]byte(in), &p); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%+v\n", p)

	in = "name=John,age=23,adult=true name=Bob,adult=true adult=true,age=30"
	var pp []person
	if err := tuples.Unmarshal([]byte(in), &pp); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%+v\n", pp)

	in = "name=John,lname=Doe,age=17 height=170,weight=50"
	var ppp any
	if err := tuples.Unmarshal([]byte(in), &ppp); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%+v\n", ppp)

}
Output:

[{Name:John Age:23 IsAdult:true}]
[{Name:John Age:23 IsAdult:true} {Name:Bob Age:0 IsAdult:true} {Name: Age:30 IsAdult:true}]
[map[age:17 lname:Doe name:John] map[height:170 weight:50]]

Types

type InvalidScannerOptionError

type InvalidScannerOptionError struct {
	// contains filtered or unexported fields
}

InvalidScannerOptionError describes an error that occurred while initializing scanner with invalid options.

func (*InvalidScannerOptionError) Error

func (e *InvalidScannerOptionError) Error() string

func (*InvalidScannerOptionError) Unwrap

func (e *InvalidScannerOptionError) Unwrap() error

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer).

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type MarshalError

type MarshalError struct {
	// contains filtered or unexported fields
}

MarshalError describes an error that occurred while marshaling a Go value to a tuple string.

func (*MarshalError) Error

func (e *MarshalError) Error() string

func (*MarshalError) Unwrap

func (e *MarshalError) Unwrap() error

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader describes a tuples reader.

func NewReader

func NewReader(r io.Reader, opts ...ReaderOption) (*Reader, error)

NewReader creates a new instance of the Reader. If reader creation fails it returns error.

func (*Reader) Read

func (r *Reader) Read() ([]string, error)

Read reads one tuple at a time and returns fields values in the order they appear in the string. It returns error when read fails or when reached the end of the tuples input.

Example
package main

import (
	"fmt"
	"io"
	"strings"

	"github.com/antklim/tuples"
)

func main() {
	in := "fname=John,lname=Doe,dob=2000-01-01 fname=Bob,lname=Smith,dob=2010-10-10"

	r, err := tuples.NewReader(strings.NewReader(in))
	if err != nil {
		fmt.Println(err)
	}

	for {
		tuple, err := r.Read()
		if err == io.EOF {
			break
		}

		if err != nil {
			fmt.Println(err)
		}
		fmt.Printf("%v\n", tuple)
	}

}
Output:

[John Doe 2000-01-01]
[Bob Smith 2010-10-10]

func (*Reader) ReadAll

func (r *Reader) ReadAll() (tuples [][]string, err error)

ReadAll reads all tuples from the input. It returns a slice of tuples values. It returns error when reader initialisation failed or read process failed.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/antklim/tuples"
)

func main() {
	in := "fname=John,lname=Doe,dob=2000-01-01 fname=Bob,lname=Smith,dob=2010-10-10"

	r, err := tuples.NewReader(strings.NewReader(in))
	if err != nil {
		fmt.Println(err)
	}

	v, err := r.ReadAll()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%v\n", v)

}
Output:

[[John Doe 2000-01-01] [Bob Smith 2010-10-10]]

type ReaderOption

type ReaderOption func(*readerOptions)

ReaderOption describes a reader option, i.e fields delimiter, key-value delimiter, etc.

func WithFieldsDelimiter

func WithFieldsDelimiter(d rune) ReaderOption

WithFieldsDelimiter sets a custom fields delimiter option for reader. Default delimiter is ','.

func WithKeyValueDelimiter

func WithKeyValueDelimiter(d rune) ReaderOption

WithFieldsDelimiter sets a custom key-value delimiter option for reader. Default delimiter is '='.

type ScannerError

type ScannerError struct {
	// contains filtered or unexported fields
}

ScannerError describes an error that occurred while scanning a tuple.

func (*ScannerError) Error

func (e *ScannerError) Error() string

func (*ScannerError) Unwrap

func (e *ScannerError) Unwrap() error

type UnmarshalError

type UnmarshalError struct {
	Err   error
	Value string
	Type  reflect.Type
}

UnmarshalError describes an error that occurred while unmarshaling a tuple fields values into a Go type fields.

func (*UnmarshalError) Error

func (e *UnmarshalError) Error() string

func (*UnmarshalError) Unwrap

func (e *UnmarshalError) Unwrap() error

type UnmarshalUnsupportedTypeError

type UnmarshalUnsupportedTypeError struct {
	Type reflect.Type
}

UnmarshalUnsupportedTypeError describes an unsupported field type of a value of a specific Go type.

func (*UnmarshalUnsupportedTypeError) Error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL