iterators

package
v0.70.0 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2022 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package iterators provide iterator implementations.

Summary

An iterator goal is to decouple the facts about the origin of the data, to the consumer who use the data. Most common scenario is to hide the fact if data is from a Certain DB, STDIN or from somewhere else. This helps to design data consumers that doesn't rely on the data source concrete implementation, while still able to do composition and different kind of actions on the received data stream. An Interface represent multiple data that can be 0 and infinite. As a general rule of thumb, if the consumer is not the final destination of the data stream, the consumer should use the pipeline pattern, in order to avoid bottleneck with local resources.

frameless.Iterator define a separate object that encapsulates accessing and traversing an aggregate object. Clients use an iterator to access and traverse an aggregate without knowing its representation (data structures). frameless.Iterator design inspirited by https://golang.ir/pkg/encoding/json/#Decoder

Why an Object with empty interface instead of type safe channels to represent streams

There are multiple approach to the same problem, and I only prefer this approach, because the error handling is easier trough this. In channel based pipeline pattern, you have to make sure that the information about the error is passed trough either trough some kind of separate error channel, or trough the message object it self that being passed around. If the pipeline can be composited during a certain use case, you can pass around a context.Context object to represent this. In the case of Interface pattern, this failure communicated during the individual iteration, which leaves it up to you to propagate the error forward, or handle at the place.

Resources

https://en.wikipedia.org/wiki/Iterator_pattern https://en.wikipedia.org/wiki/Pipeline_(software)

Index

Examples

Constants

View Source
const Break frameless.Error = `iterators:break`
View Source
const (
	// ErrClosed is the value that will be returned if a iterator has been closed but next decode is called
	ErrClosed frameless.Error = "Closed"
)

Variables

This section is empty.

Functions

func Collect

func Collect[T any](i frameless.Iterator[T]) (vs []T, err error)

func Count

func Count[T any](i frameless.Iterator[T]) (total int, err error)

Count will iterate over and count the total iterations number

Good when all you want is count all the elements in an iterator but don't want to do anything else.

func Errorf

func Errorf[T any](format string, a ...interface{}) frameless.Iterator[T]

Errorf behaves exactly like fmt.Errorf but returns the error wrapped as iterator

func First

func First[T any](i frameless.Iterator[T]) (value T, found bool, err error)

First decode the first next value of the iterator and close the iterator

func ForEach

func ForEach[T any](i frameless.Iterator[T], fn func(T) error) (rErr error)

func Last

func Last[T any](i frameless.Iterator[T]) (value T, found bool, err error)

func Pipe added in v0.63.0

func Pipe[T any]() (*PipeIn[T], *PipeOut[T])

Pipe return a receiver and a sender. This can be used with resources that

Example
package main

import (
	"github.com/adamluzsi/frameless/iterators"
)

func main() {
	var (
		i *iterators.PipeIn[int]
		o *iterators.PipeOut[int]
	)

	i, o = iterators.Pipe[int]()
	_ = i // use it to send values
	_ = o // use it to consume values on each iteration (iter.Next())
}
Output:

func Reduce added in v0.69.0

func Reduce[
	T, Result any,
	BLK func(Result, T) Result |
		func(Result, T) (Result, error),
](i frameless.Iterator[T], initial Result, blk BLK) (rv Result, rErr error)

func WithCallback

func WithCallback[T any](i frameless.Iterator[T], c Callback) frameless.Iterator[T]

Types

type BatchConfig added in v0.69.0

type BatchConfig struct {
	// Size is the max amount of element that a batch will contains.
	// Default batch Size is 100.
	Size int
	// Timeout is batching wait timout duration that the batching process is willing to wait for, before starting to build a new batch.
	// Default batch Timeout is 100 Millisecond.
	Timeout time.Duration
}

type BatchIter added in v0.69.0

type BatchIter[T any] struct {
	Iterator frameless.Iterator[T]
	Config   BatchConfig
	// contains filtered or unexported fields
}

func Batch added in v0.69.0

func Batch[T any](i frameless.Iterator[T], c BatchConfig) *BatchIter[T]

func (*BatchIter[T]) Close added in v0.69.0

func (i *BatchIter[T]) Close() error

func (*BatchIter[T]) Err added in v0.69.0

func (i *BatchIter[T]) Err() error

Err return the cause if for some reason by default the More return false all the time

func (*BatchIter[T]) Init added in v0.69.0

func (i *BatchIter[T]) Init()

func (*BatchIter[T]) Next added in v0.69.0

func (i *BatchIter[T]) Next() bool

func (*BatchIter[T]) Value added in v0.69.0

func (i *BatchIter[T]) Value() []T

Value returns the current value in the iterator. The action should be repeatable without side effect.

type Callback

type Callback struct {
	OnClose func(io.Closer) error
}

type CallbackIterator

type CallbackIterator[T any] struct {
	frameless.Iterator[T]
	Callback
}

func (*CallbackIterator[T]) Close

func (i *CallbackIterator[T]) Close() error

type ConcurrentAccessIterator

type ConcurrentAccessIterator[T any] struct {
	frameless.Iterator[T]
	// contains filtered or unexported fields
}

func WithConcurrentAccess

func WithConcurrentAccess[T any](i frameless.Iterator[T]) *ConcurrentAccessIterator[T]

WithConcurrentAccess allows you to convert any iterator into one that is safe to use from concurrent access. The caveat with this, that this protection only allows 1 Decode call for each Next call.

func (*ConcurrentAccessIterator[T]) Next

func (i *ConcurrentAccessIterator[T]) Next() bool

func (*ConcurrentAccessIterator[T]) Value added in v0.63.0

func (i *ConcurrentAccessIterator[T]) Value() T

type EmptyIter added in v0.63.0

type EmptyIter[T any] struct{}

EmptyIter iterator can help achieve Null Object Pattern when no value is logically expected and iterator should be returned

func Empty

func Empty[T any]() *EmptyIter[T]

Empty iterator is used to represent nil result with Null object pattern

Example
package main

import (
	"github.com/adamluzsi/frameless/iterators"
)

func main() {
	iterators.Empty[any]()
}
Output:

func (*EmptyIter[T]) Close added in v0.63.0

func (i *EmptyIter[T]) Close() error

func (*EmptyIter[T]) Err added in v0.63.0

func (i *EmptyIter[T]) Err() error

func (*EmptyIter[T]) Next added in v0.63.0

func (i *EmptyIter[T]) Next() bool

func (*EmptyIter[T]) Value added in v0.63.0

func (i *EmptyIter[T]) Value() T

type Encoder

type Encoder interface {
	//
	// Encode encode a simple message back to the wrapped communication channel
	//	message is an interface type because the channel communication layer and content and the serialization is up to the Encoder to implement
	//
	// If the message is a complex type that has multiple fields,
	// an exported struct that represent the content must be declared at the controller level
	// and all the presenters must based on that input for they test
	Encode(interface{}) error
}

Encoder is a scope isolation boundary. One use-case for this is for example the Presenter object that encapsulate the external resource presentation mechanism from it's user.

Scope:

receive Entities, that will be used by the creator of the Encoder

type EncoderFunc

type EncoderFunc func(interface{}) error

EncoderFunc is a wrapper to convert standalone functions into a presenter

func (EncoderFunc) Encode

func (lambda EncoderFunc) Encode(i interface{}) error

Encode implements the Encoder Interface

type ErrorIter added in v0.68.0

type ErrorIter[T any] struct {
	// contains filtered or unexported fields
}

ErrorIter iterator can be used for returning an error wrapped with iterator interface. This can be used when external resource encounter unexpected non recoverable error during query execution.

func Error

func Error[T any](err error) *ErrorIter[T]

Error returns an Interface that only can do is returning an Err and never have next element

func (*ErrorIter[T]) Close added in v0.68.0

func (i *ErrorIter[T]) Close() error

func (*ErrorIter[T]) Err added in v0.68.0

func (i *ErrorIter[T]) Err() error

func (*ErrorIter[T]) Next added in v0.68.0

func (i *ErrorIter[T]) Next() bool

func (*ErrorIter[T]) Value added in v0.68.0

func (i *ErrorIter[T]) Value() T

type FilterIter added in v0.63.0

type FilterIter[T any] struct {
	Iterator frameless.Iterator[T]
	Filter   func(T) bool
	// contains filtered or unexported fields
}

func Filter

func Filter[T any](i frameless.Iterator[T], filter func(T) bool) *FilterIter[T]
Example
package main

import (
	"log"

	"github.com/adamluzsi/frameless"

	"github.com/adamluzsi/frameless/iterators"
)

func main() {
	var iter frameless.Iterator[int]
	iter = iterators.Slice([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
	iter = iterators.Filter[int](iter, func(n int) bool { return n > 2 })

	defer iter.Close()
	for iter.Next() {
		n := iter.Value()
		_ = n
	}
	if err := iter.Err(); err != nil {
		log.Fatal(err)
	}
}
Output:

func (*FilterIter[T]) Close added in v0.63.0

func (i *FilterIter[T]) Close() error

func (*FilterIter[T]) Err added in v0.63.0

func (i *FilterIter[T]) Err() error

func (*FilterIter[T]) Next added in v0.63.0

func (i *FilterIter[T]) Next() bool

func (*FilterIter[T]) Value added in v0.63.0

func (i *FilterIter[T]) Value() T

type FuncIter added in v0.69.0

type FuncIter[T any] struct {
	NextFn func() (v T, more bool, err error)
	// contains filtered or unexported fields
}

func Func added in v0.69.0

func Func[T any](next func() (v T, more bool, err error)) *FuncIter[T]

func (*FuncIter[T]) Close added in v0.69.0

func (i *FuncIter[T]) Close() error

func (*FuncIter[T]) Err added in v0.69.0

func (i *FuncIter[T]) Err() error

func (*FuncIter[T]) Next added in v0.69.0

func (i *FuncIter[T]) Next() bool

func (*FuncIter[T]) Value added in v0.69.0

func (i *FuncIter[T]) Value() T

type ISQLRows added in v0.68.0

type ISQLRows interface {
	io.Closer
	Next() bool
	Err() error
	Scan(dest ...interface{}) error
}

type MapIter

type MapIter[T any, V any] struct {
	Iterator  frameless.Iterator[T]
	Transform MapTransformFunc[T, V]
	// contains filtered or unexported fields
}

func Map

func Map[T any, V any](iter frameless.Iterator[T], transform MapTransformFunc[T, V]) *MapIter[T, V]

Map allows you to do additional transformation on the values. This is useful in cases, where you have to alter the input value, or change the type all together. Like when you read lines from an input stream, and then you map the line content to a certain data structure, in order to not expose what steps needed in order to deserialize the input stream, thus protect the business rules from this information.

func (*MapIter[T, V]) Close

func (i *MapIter[T, V]) Close() error

func (*MapIter[T, V]) Err

func (i *MapIter[T, V]) Err() error

func (*MapIter[T, V]) Next

func (i *MapIter[T, V]) Next() bool

func (*MapIter[T, V]) Value added in v0.63.0

func (i *MapIter[T, V]) Value() V

type MapTransformFunc

type MapTransformFunc[T any, V any] func(T) (V, error)

type PipeIn added in v0.41.0

type PipeIn[T any] struct {
	// contains filtered or unexported fields
}

PipeIn provides access to feed a pipe receiver with entities

func (*PipeIn[T]) Close added in v0.41.0

func (f *PipeIn[T]) Close() error

Close will close the feed and err channels, which eventually notify the receiver that no more value expected

func (*PipeIn[T]) Error added in v0.41.0

func (f *PipeIn[T]) Error(err error)

Error send an error object to the PipeOut side, so it will be accessible with iterator.Err()

func (*PipeIn[T]) Value added in v0.63.0

func (f *PipeIn[T]) Value(v T) (ok bool)

Value send value to the PipeOut.Value. It returns if sending was possible.

type PipeOut added in v0.41.0

type PipeOut[T any] struct {
	// contains filtered or unexported fields
}

PipeOut implements iterator interface while it's still being able to receive values, used for streaming

func (*PipeOut[T]) Close added in v0.41.0

func (i *PipeOut[T]) Close() error

Close sends a signal back that no more value should be sent because receiver stop listening

func (*PipeOut[T]) Err added in v0.41.0

func (i *PipeOut[T]) Err() error

Err returns an error object that the pipe sender want to present for the pipe receiver

func (*PipeOut[T]) Next added in v0.41.0

func (i *PipeOut[T]) Next() bool

Next set the current entity for the next value returns false if no next value

func (*PipeOut[T]) Value added in v0.63.0

func (i *PipeOut[T]) Value() T

Value will link the current buffered value to the pointer value that is given as "e"

type SQLRowMapper

type SQLRowMapper[T any] interface {
	Map(s SQLRowScanner) (T, error)
}

type SQLRowMapperFunc

type SQLRowMapperFunc[T any] func(SQLRowScanner) (T, error)

func (SQLRowMapperFunc[T]) Map

func (fn SQLRowMapperFunc[T]) Map(s SQLRowScanner) (T, error)

type SQLRowScanner

type SQLRowScanner interface {
	Scan(...interface{}) error
}

type SQLRowsIter added in v0.68.0

type SQLRowsIter[T any] struct {
	Rows   ISQLRows
	Mapper SQLRowMapper[T]
	// contains filtered or unexported fields
}

SQLRowsIter allow you to use the same iterator pattern with sql.Rows structure. it allows you to do dynamic filtering, pipeline/middleware pattern on your sql results by using this wrapping around it. it also makes testing easier with the same Interface interface.

func SQLRows

func SQLRows[T any](rows ISQLRows, mapper SQLRowMapper[T]) *SQLRowsIter[T]

func (*SQLRowsIter[T]) Close added in v0.68.0

func (i *SQLRowsIter[T]) Close() error

func (*SQLRowsIter[T]) Err added in v0.68.0

func (i *SQLRowsIter[T]) Err() error

func (*SQLRowsIter[T]) Next added in v0.68.0

func (i *SQLRowsIter[T]) Next() bool

func (*SQLRowsIter[T]) Value added in v0.68.0

func (i *SQLRowsIter[T]) Value() T

type ScannerIter added in v0.68.0

type ScannerIter[T string | []byte] struct {
	*bufio.Scanner
	Closer io.Closer
	// contains filtered or unexported fields
}

func Scanner

func Scanner[T string | []byte](s *bufio.Scanner, closer io.Closer) *ScannerIter[T]

func (*ScannerIter[T]) Close added in v0.68.0

func (i *ScannerIter[T]) Close() error

func (*ScannerIter[T]) Err added in v0.68.0

func (i *ScannerIter[T]) Err() error

func (*ScannerIter[T]) Next added in v0.68.0

func (i *ScannerIter[T]) Next() bool

func (*ScannerIter[T]) Value added in v0.68.0

func (i *ScannerIter[T]) Value() T

type SingleValueIter added in v0.68.0

type SingleValueIter[T any] struct {
	V T
	// contains filtered or unexported fields
}

func SingleValue added in v0.63.0

func SingleValue[T any](v T) *SingleValueIter[T]

SingleValue creates an iterator that can return one single element and will ensure that Next can only be called once.

func (*SingleValueIter[T]) Close added in v0.68.0

func (i *SingleValueIter[T]) Close() error

func (*SingleValueIter[T]) Err added in v0.68.0

func (i *SingleValueIter[T]) Err() error

func (*SingleValueIter[T]) Next added in v0.68.0

func (i *SingleValueIter[T]) Next() bool

func (*SingleValueIter[T]) Value added in v0.68.0

func (i *SingleValueIter[T]) Value() T

type SliceIter added in v0.68.0

type SliceIter[T any] struct {
	Slice []T
	// contains filtered or unexported fields
}

func Slice

func Slice[T any](slice []T) *SliceIter[T]

func (*SliceIter[T]) Close added in v0.68.0

func (i *SliceIter[T]) Close() error

func (*SliceIter[T]) Err added in v0.68.0

func (i *SliceIter[T]) Err() error

func (*SliceIter[T]) Next added in v0.68.0

func (i *SliceIter[T]) Next() bool

func (*SliceIter[T]) Value added in v0.68.0

func (i *SliceIter[T]) Value() T

type StubIter added in v0.68.0

type StubIter[T any] struct {
	Iterator  frameless.Iterator[T]
	StubValue func() T
	StubClose func() error
	StubNext  func() bool
	StubErr   func() error
}

func Stub added in v0.68.0

func Stub[T any](i frameless.Iterator[T]) *StubIter[T]

func (*StubIter[T]) Close added in v0.68.0

func (m *StubIter[T]) Close() error

func (*StubIter[T]) Err added in v0.68.0

func (m *StubIter[T]) Err() error

func (*StubIter[T]) Next added in v0.68.0

func (m *StubIter[T]) Next() bool

func (*StubIter[T]) ResetClose added in v0.68.0

func (m *StubIter[T]) ResetClose()

func (*StubIter[T]) ResetErr added in v0.68.0

func (m *StubIter[T]) ResetErr()

func (*StubIter[T]) ResetNext added in v0.68.0

func (m *StubIter[T]) ResetNext()

func (*StubIter[T]) ResetValue added in v0.68.0

func (m *StubIter[T]) ResetValue()

func (*StubIter[T]) Value added in v0.68.0

func (m *StubIter[T]) Value() T

Jump to

Keyboard shortcuts

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