iterators

package
v0.166.2 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

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

Examples

Constants

View Source
const Break errorkit.Error = `iterators:break`

Variables

This section is empty.

Functions

func Collect

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

func Count

func Count[T any](i 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 First

func First[T any](i 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 Iterator[T], fn func(T) error) (rErr error)

func Last

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

func Must added in v0.107.0

func Must[T any](v T, err error) T

func Pipe

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/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 Callback

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

type CallbackIterator

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

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 Batch

func Batch[T any](iter Iterator[T], size int) Iterator[[]T]

func BatchWithTimeout added in v0.126.4

func BatchWithTimeout[T any](i Iterator[T], size int, timeout time.Duration) Iterator[[]T]

func BufioScanner added in v0.107.0

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

func Empty

func Empty[T any]() Iterator[T]

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

func Error[T any](err error) Iterator[T]

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

func Errorf

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

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

func Filter

func Filter[T any](i Iterator[T], filter func(T) bool) Iterator[T]
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 Func

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

func Limit added in v0.91.0

func Limit[V any](iter Iterator[V], n int) Iterator[V]

func Map

func Map[To any, From any](iter Iterator[From], transform func(From) (To, error)) Iterator[To]

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 Offset added in v0.91.0

func Offset[V any](iter Iterator[V], offset int) Iterator[V]

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

func SingleValue[T any](v T) Iterator[T]

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

func Slice

func Slice[T any](slice []T) Iterator[T]

func WithCallback

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

func WithConcurrentAccess

func WithConcurrentAccess[T any](i Iterator[T]) Iterator[T]

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

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

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

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

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

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

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

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

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

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 StubIter

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

func Stub

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

func (*StubIter[T]) Close

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

func (*StubIter[T]) Err

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

func (*StubIter[T]) Next

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

func (*StubIter[T]) ResetClose

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

func (*StubIter[T]) ResetErr

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

func (*StubIter[T]) ResetNext

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

func (*StubIter[T]) ResetValue

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

func (*StubIter[T]) Value

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

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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