bulkerrs

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2020 License: GPL-3.0 Imports: 3 Imported by: 0

README

Go Report Card CircleCI

bulkerrs

import "github.com/eurielec/bulkerrs"

This package provides a simple and effective way to collect errors while simplifies the flow complexity of sequential and conditional safety checks.

The exported 'NewErr' and 'NewErrOr' alows initialization with or without a previous 'Errs'. Theses functions work like a wrap around the built-in and 'juju/errors' constructor functions.

Once initialized, 'errs.NewErr' and 'errs.NewErrWithCause' work as a replacement of 'errors.NewErr' and 'errors.NewErrWithCause' that appends the generated jujuErr to the inner errors. Also the function 'errs.Append' appends the submitted error arguments to the inner slice.

A primary use case for this library is to append multiple errors while doing a sequence of checkings.

errs := make([]error, 0)
if err := checkFunc1(); err != nil {
  errs = append(errs, err)
}

if err := checkFunc2(); err != nil {
  errs = append(errs, err)
}

Would become with github.com/juju/errors:

errs := make([]error, 0)
if err := checkFunc1(); err != nil {
  errs = append(errs, errors.Trace(err))
}

if err := checkFunc2(); err != nil {
  errs = append(errs, errors.Annotate(err, "more context"))
  // Adding annotation to the error
}

And with bulkerrs:

errs := bulkerrs.NewErrOr(checkFunc1())
errs.NewErrWithCause(checkFunc2(), "more context")

There's no longer need to check if the error is nil.

Additionally, bulkerrs makes easy to integrate the errors appendings in the application control flow:

errs := make([]error, 0)
if err1 := checkFunc1(); err1 != nil {
  errs = append(errs, err1)
  if err1_1 := checkFunc1_1(); err1_1 != nil {
    errs = append(errs, err1_1)
  }
} else if err2 := checkFunc2(); err2 != nil {
  errs = append(errs, err2)
  if err2_1 := checkFunc2_1(); err2_1 != nil {
    errs = append(errs, err2_1)
  }
} else {
  if errx_1 := checkFuncx(); errx_1 != nil {
    errs = append(errs, errx_1)
  } else {
    return nil
  }
}
return &errs

Would become:

errs := bulkerrs.NewErr()
if errs.Append(checkFunc1()) {
  errs.Append(checkFunc1_1())
} else if errs.Append(checkFunc2()) {
  errs.Append(checkFunc2_1())
} else {
  errs.Append(checkFuncx())
}
// return an error if len(errs.errors) > 0 or nil
return errs.ToError()

And if needed, like in github.com/juju/errors, it's possible to add extra context, and have an advanced control of the application flow:

errs := bulkerrs.NewErr()
if err1 := checkFunc1(); errs.AppendIfX(err1 != nil, errors.Annotate, "more context1", err1) {
  errs.Append(checkFunc1_1())
} else if err2 := checkFunc2(); errs.AppendIfX(err2 == nil, errors.Annotate, "This should have failed but didn't", nil) {
  errs.Append(checkFunc2_1())
} else {
  errx := checkFuncx()
  // add extra error types
  errs.AppendIfX(errx != nil, errors.NewNotValid, "more context", errx)
}
return errs.ToError()

When you want to check to see if an error is of a particular type, a helper function is normally exported by the package that returned the error, like the 'os' package does. The underlying cause of the error is available using the 'Cause' function. os.IsNotExist(errors.Cause(err)) The result of the 'Error()' call on an annotated error is the annotations joined with colons, then the result of the 'Error()' method for the underlying error that was the cause. err := errors.Errorf("original") err = errors.Annotatef(err, "context") err = errors.Annotatef(err, "more context") err.Error() -> "more context: context: original" Obviously recording the file, line and functions is not very useful if you cannot get them back out again. errors.ErrorStack(err) will return something like: first error github.com/juju/errors/annotation_test.go:193: github.com/juju/errors/annotation_test.go:194: annotation github.com/juju/errors/annotation_test.go:195: github.com/juju/errors/annotation_test.go:196: more context github.com/juju/errors/annotation_test.go:197: The first error was generated by an external system, so there was no location associated. The second, fourth, and last lines were generated with Trace calls, and the other two through Annotate. Sometimes when responding to an error you want to return a more specific error for the situation. if err := FindField(field); err != nil { return errors.Wrap(err, errors.NotFoundf(field)) } This returns an error where the complete error stack is still available, and 'errors.Cause()' will return the 'NotFound' error.

Index

func IsAlreadyExists

func IsAlreadyExists(err error) bool

func IsBadRequest

func IsBadRequest(err error) bool

func IsForbidden

func IsForbidden(err error) bool

func IsMethodNotAllowed

func IsMethodNotAllowed(err error) bool

func IsNotAssigned

func IsNotAssigned(err error) bool

func IsNotFound

func IsNotFound(err error) bool

func IsNotImplemented

func IsNotImplemented(err error) bool

func IsNotProvisioned

func IsNotProvisioned(err error) bool

func IsNotSupported

func IsNotSupported(err error) bool

func IsNotValid

func IsNotValid(err error) bool

func IsTimeout

func IsTimeout(err error) bool

func IsUnauthorized

func IsUnauthorized(err error) bool

func IsUserNotFound

func IsUserNotFound(err error) bool

type Errs

Errs holds an array of JujuErr (juju/errors).

It may be embedded in also custom error types that have been converted to JujuErr.

type Errs struct {
    // contains filtered or unexported fields
}
func Concat
func Concat(errs ...error) Errs
func NewErr
func NewErr() Errs
func NewErrOr
func NewErrOr(err error) Errs
func (*Errs) Append
func (e *Errs) Append(errs ...error) bool
func (*Errs) AppendIf
func (e *Errs) AppendIf(condition bool, msg string) bool

Appends error if condition, returns condition

func (*Errs) AppendIfX
func (e *Errs) AppendIfX(condition bool, newErr NewXFn, msg string, other error) bool
func (*Errs) Error
func (e *Errs) Error() string
func (*Errs) Errors
func (e *Errs) Errors() []string
func (Errs) Format
func (e Errs) Format(s fmt.State, verb rune)
func (*Errs) InnerErrors
func (e *Errs) InnerErrors() []error
func (*Errs) NewErr
func (e *Errs) NewErr(format string, args ...interface{})
func (*Errs) NewErrWithCause
func (e *Errs) NewErrWithCause(other error, format string, args ...interface{})
func (Errs) ToError
func (e Errs) ToError() error

type IsXFn

type IsXFn func(err error) bool

type JujuErr

If an error complies this interface, then it's a juju error :)

type JujuErr interface {
    Cause() error
    Error() string
    Format(fmt.State, rune)
    Location() (string, int)
    Message() string
    SetLocation(int)
    StackTrace() []string
    Underlying() error
}

type NewXFn

Juju Error function interfaces

type NewXFn func(error, string) error

Generated by gomarkdoc

Documentation

Overview

This package provides a simple and effective way to collect errors while simplifies the flow complexity of sequential and conditional safety checks.

The exported 'NewErr' and 'NewErrOr' alows initialization with or without a previous 'Errs'. Theses functions work like a wrap around the built-in and 'juju/errors' constructor functions.

Once initialized, 'errs.NewErr' and 'errs.NewErrWithCause' work as a replacement of 'errors.NewErr' and 'errors.NewErrWithCause' that appends the generated jujuErr to the inner errors. Also the function 'errs.Append' appends the submitted error arguments to the inner slice.

A primary use case for this library is to append multiple errors while doing a sequence of checkings.

errs := make([]error, 0)
if err := checkFunc1(); err != nil {
  errs = append(errs, err)
}

if err := checkFunc2(); err != nil {
  errs = append(errs, err)
}

Would become with github.com/juju/errors:

errs := make([]error, 0)
if err := checkFunc1(); err != nil {
  errs = append(errs, errors.Trace(err))
}

if err := checkFunc2(); err != nil {
  errs = append(errs, errors.Annotate(err, "more context"))
  // Adding annotation to the error
}

And with bulkerrs:

errs := bulkerrs.NewErrOr(checkFunc1())
errs.NewErrWithCause(checkFunc2(), "more context")

There's no longer need to check if the error is nil.

Additionally, bulkerrs makes easy to integrate the errors appendings in the application control flow:

errs := make([]error, 0)
if err1 := checkFunc1(); err1 != nil {
  errs = append(errs, err1)
  if err1_1 := checkFunc1_1(); err1_1 != nil {
    errs = append(errs, err1_1)
  }
} else if err2 := checkFunc2(); err2 != nil {
  errs = append(errs, err2)
  if err2_1 := checkFunc2_1(); err2_1 != nil {
    errs = append(errs, err2_1)
  }
} else {
  if errx_1 := checkFuncx(); errx_1 != nil {
    errs = append(errs, errx_1)
  } else {
    return nil
  }
}
return &errs

Would become:

errs := bulkerrs.NewErr()
if errs.Append(checkFunc1()) {
  errs.Append(checkFunc1_1())
} else if errs.Append(checkFunc2()) {
  errs.Append(checkFunc2_1())
} else {
  errs.Append(checkFuncx())
}
// return an error if len(errs.errors) > 0 or nil
return errs.ToError()

And if needed, like in github.com/juju/errors, it's possible to add extra context, and have an advanced control of the application flow:

errs := bulkerrs.NewErr()
if err1 := checkFunc1(); errs.AppendIfX(err1 != nil, errors.Annotate, "more context1", err1) {
  errs.Append(checkFunc1_1())
} else if err2 := checkFunc2(); errs.AppendIfX(err2 == nil, errors.Annotate, "This should have failed but didn't", nil) {
  errs.Append(checkFunc2_1())
} else {
  errx := checkFuncx()
  // add extra error types
  errs.AppendIfX(errx != nil, errors.NewNotValid, "more context", errx)
}
return errs.ToError()

When you want to check to see if an error is of a particular type, a helper function is normally exported by the package that returned the error, like the 'os' package does. The underlying cause of the error is available using the 'Cause' function.

os.IsNotExist(errors.Cause(err))

The result of the 'Error()' call on an annotated error is the annotations joined with colons, then the result of the 'Error()' method for the underlying error that was the cause.

err := errors.Errorf("original")
err = errors.Annotatef(err, "context")
err = errors.Annotatef(err, "more context")
err.Error() -> "more context: context: original"

Obviously recording the file, line and functions is not very useful if you cannot get them back out again.

errors.ErrorStack(err)

will return something like:

first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:

The first error was generated by an external system, so there was no location associated. The second, fourth, and last lines were generated with Trace calls, and the other two through Annotate. Sometimes when responding to an error you want to return a more specific error for the situation.

    if err := FindField(field); err != nil {
	    return errors.Wrap(err, errors.NotFoundf(field))
	}

This returns an error where the complete error stack is still available, and 'errors.Cause()' will return the 'NotFound' error.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsAlreadyExists

func IsAlreadyExists(err error) bool

func IsBadRequest

func IsBadRequest(err error) bool

func IsForbidden

func IsForbidden(err error) bool

func IsMethodNotAllowed

func IsMethodNotAllowed(err error) bool

func IsNotAssigned

func IsNotAssigned(err error) bool

func IsNotFound

func IsNotFound(err error) bool

func IsNotImplemented

func IsNotImplemented(err error) bool

func IsNotProvisioned

func IsNotProvisioned(err error) bool

func IsNotSupported

func IsNotSupported(err error) bool

func IsNotValid

func IsNotValid(err error) bool

func IsTimeout

func IsTimeout(err error) bool

func IsUnauthorized

func IsUnauthorized(err error) bool

func IsUserNotFound

func IsUserNotFound(err error) bool

Types

type Errs

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

Errs holds an array of JujuErr (juju/errors).

It may be embedded in also custom error types that have been converted to JujuErr.

func Concat

func Concat(errs ...error) Errs

func NewErr

func NewErr() Errs

func NewErrOr

func NewErrOr(err error) Errs

func (*Errs) Append

func (e *Errs) Append(errs ...error) bool

func (*Errs) AppendIf

func (e *Errs) AppendIf(condition bool, msg string) bool

Appends error if condition, returns condition

func (*Errs) AppendIfX

func (e *Errs) AppendIfX(condition bool, newErr NewXFn, msg string, other error) bool

func (*Errs) Error

func (e *Errs) Error() string

func (*Errs) Errors

func (e *Errs) Errors() []string

func (Errs) Format

func (e Errs) Format(s fmt.State, verb rune)

func (*Errs) InnerErrors

func (e *Errs) InnerErrors() []error

func (*Errs) NewErr

func (e *Errs) NewErr(format string, args ...interface{})

func (*Errs) NewErrWithCause

func (e *Errs) NewErrWithCause(other error, format string, args ...interface{})

func (Errs) ToError

func (e Errs) ToError() error

type IsXFn

type IsXFn func(err error) bool

type JujuErr

type JujuErr interface {
	Cause() error
	Error() string
	Format(fmt.State, rune)
	Location() (string, int)
	Message() string
	SetLocation(int)
	StackTrace() []string
	Underlying() error
}

If an error complies this interface, then it's a juju error :)

type NewXFn

type NewXFn func(error, string) error

Juju Error function interfaces

Jump to

Keyboard shortcuts

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