Documentation ¶
Overview ¶
Package iterators provide iterator implementations.
Summary ¶
An Iterator's goal is to decouple the origin of the data from the consumer who uses that data. Most commonly, iterators hide whether the data comes from a specific database, standard input, or elsewhere. This approach helps to design data consumers that are not dependent on the concrete implementation of the data source, while still allowing for the composition and various actions on the received data stream. An Iterator represents an iterable list of element, which length is not known until it is fully iterated, thus can range from zero to infinity. As a rule of thumb, if the consumer is not the final destination of the data stream, it should use the pipeline pattern to avoid bottlenecks with local resources such as memory.
Resources ¶
https://en.wikipedia.org/wiki/Iterator_pattern https://en.wikipedia.org/wiki/Pipeline_(software)
Index ¶
- Constants
- func Collect[T any](i Iterator[T]) (vs []T, err error)
- func Count[T any](i Iterator[T]) (total int, err error)
- func First[T any](i Iterator[T]) (value T, found bool, err error)
- func ForEach[T any](i Iterator[T], fn func(T) error) (rErr error)
- func Last[T any](i Iterator[T]) (value T, found bool, err error)
- func Must[T any](v T, err error) T
- func Pipe[T any]() (*PipeIn[T], *PipeOut[T])
- func Reduce[R, T any, FN ...](i Iterator[T], initial R, blk FN) (result R, rErr error)
- type Callback
- type CallbackIterator
- type Iterator
- func Batch[T any](iter Iterator[T], size int) Iterator[[]T]
- func BatchWithTimeout[T any](i Iterator[T], size int, timeout time.Duration) Iterator[[]T]
- func BufioScanner[T string | []byte](s *bufio.Scanner, closer io.Closer) Iterator[T]
- func Empty[T any]() Iterator[T]
- func Error[T any](err error) Iterator[T]
- func Errorf[T any](format string, a ...interface{}) Iterator[T]
- func Filter[T any](i Iterator[T], filter func(T) bool) Iterator[T]
- func Func[T any](next func() (v T, more bool, err error)) Iterator[T]
- func Limit[V any](iter Iterator[V], n int) Iterator[V]
- func Map[To any, From any](iter Iterator[From], transform func(From) (To, error)) Iterator[To]
- func Offset[V any](iter Iterator[V], offset int) Iterator[V]
- func SQLRows[T any](rows sqlRows, mapper SQLRowMapper[T]) Iterator[T]
- func SingleValue[T any](v T) Iterator[T]
- func Slice[T any](slice []T) Iterator[T]
- func WithCallback[T any](i Iterator[T], c Callback) Iterator[T]
- func WithConcurrentAccess[T any](i Iterator[T]) Iterator[T]
- type PipeIn
- type PipeOut
- type SQLRowMapper
- type SQLRowMapperFunc
- type SQLRowScanner
- type StubIter
Examples ¶
Constants ¶
const Break errorkit.Error = `iterators:break`
Variables ¶
This section is empty.
Functions ¶
func Count ¶
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 Pipe ¶
Pipe return a receiver and a sender. This can be used with resources that
Example ¶
package main import ( "github.com/adamluzsi/frameless/ports/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 ¶
func Reduce[ R, T any, FN func(R, T) R | func(R, T) (R, error), ](i Iterator[T], initial R, blk FN) (result R, rErr error)
Example ¶
package main import ( "strconv" "github.com/adamluzsi/frameless/ports/iterators" ) func main() { raw := iterators.Slice([]string{"1", "2", "42"}) _, _ = iterators.Reduce[[]int](raw, nil, func(vs []int, raw string) ([]int, error) { v, err := strconv.Atoi(raw) if err != nil { return nil, err } return append(vs, v), nil }) }
Output:
Types ¶
type CallbackIterator ¶
func (*CallbackIterator[T]) Close ¶
func (i *CallbackIterator[T]) Close() error
type Iterator ¶
type Iterator[V any] interface { // Closer is required to make it able to cancel iterators where resources are being used behind the scene // for all other cases where the underling io is handled on a higher level, it should simply return nil io.Closer // Err return the error cause. Err() error // Next will ensure that Value returns the next item when executed. // If the next value is not retrievable, Next should return false and ensure Err() will return the error cause. Next() bool // Value returns the current value in the iterator. // The action should be repeatable without side effects. Value() V }
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). Interface design inspirited by https://golang.org/pkg/encoding/json/#Decoder https://en.wikipedia.org/wiki/Iterator_pattern
Example ¶
package main import ( "github.com/adamluzsi/frameless/ports/iterators" ) func main() { var iter iterators.Iterator[int] defer iter.Close() for iter.Next() { v := iter.Value() _ = v } if err := iter.Err(); err != nil { // handle error } }
Output:
func BatchWithTimeout ¶ added in v0.126.4
func BufioScanner ¶ added in v0.107.0
func Empty ¶
Empty iterator is used to represent nil result with Null object pattern
Example ¶
package main import ( "github.com/adamluzsi/frameless/ports/iterators" ) func main() { iterators.Empty[any]() }
Output:
func Error ¶
Error returns an Interface that only can do is returning an Err and never have next element
func Filter ¶
Example ¶
package main import ( "log" "github.com/adamluzsi/frameless/ports/iterators" ) func main() { var iter iterators.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 Map ¶
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.
Example ¶
package main import ( "strconv" "github.com/adamluzsi/frameless/ports/iterators" ) func main() { rawNumbers := iterators.Slice([]string{"1", "2", "42"}) numbers := iterators.Map[int](rawNumbers, strconv.Atoi) _ = numbers }
Output:
func SQLRows ¶
func SQLRows[T any](rows sqlRows, mapper SQLRowMapper[T]) Iterator[T]
Example ¶
package main import ( "context" "database/sql" "github.com/adamluzsi/frameless/ports/iterators" ) func main() { var ( ctx context.Context db *sql.DB ) userIDs, err := db.QueryContext(ctx, `SELECT id FROM users`) if err != nil { panic(err) } type mytype struct { asdf string } iter := iterators.SQLRows[mytype](userIDs, iterators.SQLRowMapperFunc[mytype](func(scanner iterators.SQLRowScanner) (mytype, error) { var value mytype if err := scanner.Scan(&value.asdf); err != nil { return mytype{}, err } return value, nil })) defer iter.Close() for iter.Next() { v := iter.Value() _ = v } if err := iter.Err(); err != nil { panic(err) } }
Output:
func SingleValue ¶
SingleValue creates an iterator that can return one single element and will ensure that Next can only be called once.
func WithConcurrentAccess ¶
WithConcurrentAccess allows you to convert any iterator into one that is safe to use from concurrent access. The caveat with this is that this protection only allows 1 Decode call for each Next call.
type PipeIn ¶
type PipeIn[T any] struct { // contains filtered or unexported fields }
PipeIn provides access to feed a pipe receiver with entities
func (*PipeIn[T]) Close ¶
Close will close the feed and err channels, which eventually notify the receiver that no more value expected
type PipeOut ¶
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 ¶
Close sends a signal back that no more value should be sent because receiver stop listening
func (*PipeOut[T]) Err ¶
Err returns an error object that the pipe sender want to present for the pipe receiver
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
}