errbox

package
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2024 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Example (Encoding_json_reader_broken)
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"
	"testing/iotest"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const readerBroken = `{
		"foo": "bar",
		"baz": ["yay", "nay", 5, "wow"]`

	dec := errbox.NewJsonDecoder(
		json.NewDecoder(
			io.MultiReader(
				strings.NewReader(readerBroken),
				iotest.ErrReader(errors.New("sample")),
			),
		),
	)

	for t := range dec.Iter() {
		fmt.Printf("%v\n", t)
	}
	fmt.Printf("stored error: %v\n", dec.Err())
}
Output:

{
foo
bar
baz
[
yay
nay
5
wow
]
stored error: sample
Example (Encoding_json_semantically_broken)
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const semanticallyBroken = `{
		"foo": "bar",
		"baz": ["yay", "nay", 5, "wow"]
	}`

	dec := errbox.NewJsonDecoder(json.NewDecoder(strings.NewReader(semanticallyBroken)))

	var depth int
	for t := range dec.Iter() {
		if depth == 1 && t == "baz" {
			// read 1 ahead.
			t, err := dec.Dec.Token()
			if err != nil {
				panic(err)
			}
			if t != json.Delim('[') {
				panic("??")
			}
			var yayyay string
			for dec.Dec.More() {
				err = dec.Dec.Decode(&yayyay)
				if err == nil {
					fmt.Printf("yay? = %s\n", yayyay)
				} else {
					fmt.Printf("yay err = %v\n", err)
				}
			}
		}
		switch t {
		case json.Delim('{'), json.Delim('['):
			depth++
		case json.Delim('}'), json.Delim(']'):
			depth--
		}
	}
	fmt.Printf("stored error: %v\n", dec.Err())
	_, err := dec.Dec.Token()
	fmt.Printf("eof: %t\n", err == io.EOF)
}
Output:

yay? = yay
yay? = nay
yay err = json: cannot unmarshal number into Go value of type string
yay? = wow
stored error: <nil>
eof: true
Example (Encoding_json_syntactically_broken)
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const syntacticallyBroken = `{
		"foo": "bar",
		"baz": ["yay", "nay", 5, "wow"],
		"broken": {
	}`

	dec := errbox.NewJsonDecoder(json.NewDecoder(strings.NewReader(syntacticallyBroken)))

	for t := range dec.Iter() {
		fmt.Printf("%v\n", t)
	}
	fmt.Printf("stored error: %v\n", dec.Err())
	_, err := dec.Dec.Token()
	fmt.Printf("eof: %t\n", err == io.EOF)
}
Output:

{
foo
bar
baz
[
yay
nay
5
wow
]
broken
{
}
stored error: <nil>
eof: true
Example (Encoding_xml_reader_broken)
package main

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"strings"
	"testing/iotest"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const readerBroken = `
	<root>
		<self/>
		<foo>bar</foo>
		<baz>5</baz>
		<baz>23</baz>
		<baz>yay</baz>
		<baz>49`

	dec := errbox.NewXmlDecoder(
		xml.NewDecoder(
			io.MultiReader(
				strings.NewReader(strings.TrimSpace(readerBroken)),
				iotest.ErrReader(errors.New("sample")),
			),
		),
	)

	for t := range dec.Iter() {
		fmt.Printf("%#v\n", t)
	}
	fmt.Printf("stored err: %v\n", dec.Err())
}
Output:

xml.StartElement{Name:xml.Name{Space:"", Local:"root"}, Attr:[]xml.Attr{}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"self"}, Attr:[]xml.Attr{}}
xml.EndElement{Name:xml.Name{Space:"", Local:"self"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"foo"}, Attr:[]xml.Attr{}}
xml.CharData{0x62, 0x61, 0x72}
xml.EndElement{Name:xml.Name{Space:"", Local:"foo"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x35}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x32, 0x33}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x79, 0x61, 0x79}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x34, 0x39}
stored err: sample
Example (Encoding_xml_semantically_broken)
package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"strings"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const semanticallyBroken = `
	<root>
		<self/>
		<foo>bar</foo>
		<baz>5</baz>
		<baz>23</baz>
		<baz>yay</baz>
		<baz>49</baz>
	</root>`

	dec := errbox.NewXmlDecoder(xml.NewDecoder(strings.NewReader(strings.TrimSpace(semanticallyBroken))))

	var depth int
	for t := range dec.Iter() {
		var ok bool
		tok, ok := t.(xml.StartElement)
		if ok {
			if depth == 1 && tok.Name.Local == "baz" {
				var yayyay int
				err := dec.Dec.DecodeElement(&yayyay, &tok)
				if err == nil {
					fmt.Printf("yay? = %d\n", yayyay)
				} else {
					fmt.Printf("yay err = %v\n", err)
				}
				continue
			}
			depth++
		}
		_, ok = t.(xml.EndElement)
		if ok {
			depth--
		}
	}
	fmt.Printf("stored error: %v\n", dec.Err())
	_, err := dec.Dec.Token()
	fmt.Printf("eof: %t\n", err == io.EOF)
}
Output:

yay? = 5
yay? = 23
yay err = strconv.ParseInt: parsing "yay": invalid syntax
yay? = 49
stored error: <nil>
eof: true
Example (Encoding_xml_syntactically_broken)
package main

import (
	"encoding/xml"
	"fmt"
	"strings"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
)

func main() {
	const syntacticallyBroken = `
	<root>
		<self/>
		<foo>bar</foo>
		<baz>5</baz>
		<baz>23</baz>
		<baz>yay</baz>
		<baz>49`

	dec := errbox.NewXmlDecoder(xml.NewDecoder(strings.NewReader(strings.TrimSpace(syntacticallyBroken))))

	for t := range dec.Iter() {
		fmt.Printf("%#v\n", t)
	}
	fmt.Printf("stored err: %v\n", dec.Err())
}
Output:

xml.StartElement{Name:xml.Name{Space:"", Local:"root"}, Attr:[]xml.Attr{}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"self"}, Attr:[]xml.Attr{}}
xml.EndElement{Name:xml.Name{Space:"", Local:"self"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"foo"}, Attr:[]xml.Attr{}}
xml.CharData{0x62, 0x61, 0x72}
xml.EndElement{Name:xml.Name{Space:"", Local:"foo"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x35}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x32, 0x33}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x79, 0x61, 0x79}
xml.EndElement{Name:xml.Name{Space:"", Local:"baz"}}
xml.CharData{0xa, 0x9, 0x9}
xml.StartElement{Name:xml.Name{Space:"", Local:"baz"}, Attr:[]xml.Attr{}}
xml.CharData{0x34, 0x39}
stored err: XML syntax error on line 7: unexpected EOF
Example (Sql_rows_row_error)
package main

import (
	"fmt"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
	"github.com/ngicks/go-iterator-helper/internal/testhelper"
)

func main() {
	mock := testhelper.OpenMockDB(true)
	defer mock.Close()

	boxed := errbox.NewSqlRows(testhelper.QueryRows(mock), testhelper.Scan)
	for row := range boxed.Iter() {
		fmt.Printf("row = %#v\n", row)
	}
	fmt.Printf("stored err: %v\n", boxed.Err())
}
Output:

row = testhelper.TestRow{Id:1, Title:"post 1", Body:"hello"}
row = testhelper.TestRow{Id:2, Title:"post 2", Body:"world"}
stored err: mock error
Example (Sql_rows_scan_error)
package main

import (
	"database/sql"
	"errors"
	"fmt"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
	"github.com/ngicks/go-iterator-helper/internal/testhelper"
)

func main() {
	scanErr := errors.New("scan")

	mock := testhelper.OpenMockDB(true)
	defer mock.Close()

	var count int
	boxed := errbox.NewSqlRows(
		testhelper.QueryRows(mock),
		func(r *sql.Rows) (testhelper.TestRow, error) {
			count++
			if count > 1 {
				return *new(testhelper.TestRow), scanErr
			}
			return testhelper.Scan(r)
		},
	)
	for row := range boxed.Iter() {
		fmt.Printf("row = %#v\n", row)
	}
	fmt.Printf("stored err: %v\n", boxed.Err())
}
Output:

row = testhelper.TestRow{Id:1, Title:"post 1", Body:"hello"}
stored err: scan
Example (Sql_rows_successful)
package main

import (
	"database/sql"
	"fmt"

	"github.com/ngicks/go-iterator-helper/hiter/errbox"
	"github.com/ngicks/go-iterator-helper/internal/testhelper"
)

func main() {
	type TestRow struct {
		Id    int
		Title string
		Body  string
	}

	mock := testhelper.OpenMockDB(false)
	defer mock.Close()

	rows, err := mock.Query("SELECT id, title, body FROM posts")
	if err != nil {
		panic(err)
	}

	scanner := func(r *sql.Rows) (TestRow, error) {
		var t TestRow
		err := r.Scan(&t.Id, &t.Title, &t.Body)
		return t, err
	}

	boxed := errbox.NewSqlRows(rows, scanner)
	for row := range boxed.Iter() {
		fmt.Printf("row = %#v\n", row)
	}
	fmt.Printf("stored err: %v\n", boxed.Err())
}
Output:

row = errbox_test.TestRow{Id:1, Title:"post 1", Body:"hello"}
row = errbox_test.TestRow{Id:2, Title:"post 2", Body:"world"}
row = errbox_test.TestRow{Id:3, Title:"post 3", Body:"iter"}
stored err: <nil>

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Box

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

Box boxes an input iter.Seq2[V, error] to iter.Seq[V], by storing a first non nil error encountered. Later the error can be examined by *Box.Err.

*Box.Iter returns an iterator converted to be stateful from input iter.Seq2 by iter.Pull2. When non nil error is yielded from the iterator, Box stores the error and the boxed iterator stops without yielding paired value V. *Box.Err returns that error otherwise nil.

The zero Box is invalid and it must be allocated by New.

func New

func New[V any](seq iter.Seq2[V, error]) *Box[V]

New returns a newly allocate Box.

When a pair from seq contains non-nil error, Box discards a former value of the pair(V), then the iterator returned from Box.Iter stops.

*Box.Stop must be called to release resource regardless of usage.

func (*Box[V]) Err

func (b *Box[V]) Err() error

Err returns an error the input iterator has returned. If the iterator has not yet encountered an error, Err returns nil.

func (*Box[V]) Iter

func (b *Box[V]) Iter() iter.Seq[V]

Iter returns a stateful iterator which yields values from the input iterator.

func (*Box[V]) Stop

func (b *Box[V]) Stop()

Stop releases resources allocated by New. After calling Stop, iterators returned from Box.Iter yields nothing.

type JsonDecoder

type JsonDecoder struct {
	*Box[json.Token]
	Dec *json.Decoder
}

func NewJsonDecoder

func NewJsonDecoder(dec *json.Decoder) *JsonDecoder

type SqlRows

type SqlRows[V any] struct {
	*Box[V]
}

func NewSqlRows

func NewSqlRows[V any](rows *sql.Rows, scanner func(*sql.Rows) (V, error)) *SqlRows[V]

type XmlDecoder

type XmlDecoder struct {
	*Box[xml.Token]
	Dec *xml.Decoder
}

func NewXmlDecoder

func NewXmlDecoder(dec *xml.Decoder) *XmlDecoder

Jump to

Keyboard shortcuts

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