-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add res package with Success, PartialSuccess and Failure types.
- Loading branch information
Showing
5 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package res | ||
|
||
import ( | ||
"fmt" | ||
"github.com/jpfourny/papaya/pkg/opt" | ||
) | ||
|
||
// Failure represents a failed result. | ||
// A failed result has an error and no value. | ||
type Failure[T any] struct { | ||
Err error | ||
} | ||
|
||
// Assert that Failure[T] implements Result[T] | ||
var _ Result[any] = Failure[any]{} | ||
|
||
func (r Failure[T]) Succeeded() bool { | ||
return false | ||
} | ||
|
||
func (r Failure[T]) PartiallySucceeded() bool { | ||
return false | ||
} | ||
|
||
func (r Failure[T]) Failed() bool { | ||
return true | ||
} | ||
|
||
func (r Failure[T]) HasError() bool { | ||
return true | ||
} | ||
|
||
func (r Failure[T]) HasValue() bool { | ||
return false | ||
} | ||
|
||
func (r Failure[T]) Value() opt.Optional[T] { | ||
return opt.Empty[T]() | ||
} | ||
|
||
func (r Failure[T]) Error() opt.Optional[error] { | ||
return opt.Of(r.Err) | ||
} | ||
|
||
func (r Failure[T]) String() string { | ||
return fmt.Sprintf("Failure(%v)", r.Err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package res | ||
|
||
import ( | ||
"fmt" | ||
"github.com/jpfourny/papaya/pkg/opt" | ||
) | ||
|
||
// PartialSuccess represents a partially-successful result. | ||
// A partially successful result has a value and an error. | ||
// This is useful when a result is expected to have multiple values, and some of them are missing. | ||
type PartialSuccess[T any] struct { | ||
Val T | ||
Err error | ||
} | ||
|
||
// Assert that PartialSuccess[T] implements Result[T] | ||
var _ Result[any] = PartialSuccess[any]{} | ||
|
||
func (r PartialSuccess[T]) Succeeded() bool { | ||
return false | ||
} | ||
|
||
func (r PartialSuccess[T]) PartiallySucceeded() bool { | ||
return true | ||
} | ||
|
||
func (r PartialSuccess[T]) Failed() bool { | ||
return false | ||
} | ||
|
||
func (r PartialSuccess[T]) HasError() bool { | ||
return true | ||
} | ||
|
||
func (r PartialSuccess[T]) HasValue() bool { | ||
return true | ||
} | ||
|
||
func (r PartialSuccess[T]) Value() opt.Optional[T] { | ||
return opt.Of(r.Val) | ||
} | ||
|
||
func (r PartialSuccess[T]) Error() opt.Optional[error] { | ||
return opt.Of(r.Err) | ||
} | ||
|
||
func (r PartialSuccess[T]) String() string { | ||
return fmt.Sprintf("PartialSuccess(%#v, %v)", r.Val, r.Err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package res | ||
|
||
import ( | ||
"fmt" | ||
"github.com/jpfourny/papaya/pkg/opt" | ||
) | ||
|
||
// Result represents the result of an operation that may have a value and/or an error. | ||
// The result can be successful, failed, or partially successful. | ||
// A successful result has a value and no error. | ||
// A failed result has an error and no value. | ||
// A partially successful result has both a value and an error. | ||
// The result can be queried for its value and/or error, and for its success/failure status. | ||
type Result[T any] interface { | ||
fmt.Stringer | ||
|
||
// Succeeded returns true for a successful result; false otherwise. | ||
// A successful result is one that has a value and no error. | ||
Succeeded() bool | ||
|
||
// PartiallySucceeded returns true for a partially successful result that includes both a value and an error. | ||
// This is useful when a result is expected to have multiple values, and some of them are missing. | ||
PartiallySucceeded() bool | ||
|
||
// Failed returns true for a failed result; false otherwise. | ||
// A failed result is one that has an error and no value. | ||
Failed() bool | ||
|
||
// HasError returns true if the result has an error; false otherwise. | ||
// This is true for both failed and partially successful results. | ||
HasError() bool | ||
|
||
// HasValue returns true if the result has a value; false otherwise. | ||
// This is true for both successful and partially successful results. | ||
HasValue() bool | ||
|
||
// Value returns the value of the result as an optional. | ||
// If the result has a value, the optional is non-empty; otherwise, it is empty. | ||
Value() opt.Optional[T] | ||
|
||
// Error returns the error of the result as an optional. | ||
// If the result has an error, the optional is non-empty; otherwise, it is empty. | ||
Error() opt.Optional[error] | ||
} | ||
|
||
// OfSuccess returns a successful result with the provided value. | ||
func OfSuccess[T any](val T) Result[T] { | ||
return Success[T]{Val: val} | ||
} | ||
|
||
// OfPartialSuccess returns a partially successful result with the provided value and error. | ||
func OfPartialSuccess[T any](val T, err error) Result[T] { | ||
return PartialSuccess[T]{Val: val, Err: err} | ||
} | ||
|
||
// OfFailure returns a failed result with the provided error. | ||
func OfFailure[T any](err error) Result[T] { | ||
return Failure[T]{Err: err} | ||
} | ||
|
||
// Of returns a result with the provided value and error. | ||
// If the error is nil, the result is successful; otherwise, it is failed. | ||
// This is a convenience function that creates a successful or failed result based on the provided error. | ||
func Of[T any](val T, err error) Result[T] { | ||
if err != nil { | ||
return OfFailure[T](err) | ||
} | ||
return OfSuccess[T](val) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package res | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
) | ||
|
||
func TestOfSuccess(t *testing.T) { | ||
r := OfSuccess(42) | ||
if !r.Succeeded() { | ||
t.Errorf("expected Succeeded() to be true") | ||
} | ||
if r.PartiallySucceeded() { | ||
t.Errorf("expected PartiallySucceeded() to be false") | ||
} | ||
if r.Failed() { | ||
t.Errorf("expected Failed() to be false") | ||
} | ||
if !r.HasValue() { | ||
t.Errorf("expected HasValue() to be true") | ||
} | ||
if r.HasError() { | ||
t.Errorf("expected HasError() to be false") | ||
} | ||
if r.Value().GetOrZero() != 42 { | ||
t.Errorf("expected Value() to return 42") | ||
} | ||
if r.Error().Present() { | ||
t.Errorf("expected Error() to be empty") | ||
} | ||
if r.String() != "Success(42)" { | ||
t.Errorf("expected String() to return Success(42)") | ||
} | ||
} | ||
|
||
func TestOfFailure(t *testing.T) { | ||
r := OfFailure[any](errors.New("error")) | ||
if r.Succeeded() { | ||
t.Errorf("expected Succeeded() to be false") | ||
} | ||
if r.PartiallySucceeded() { | ||
t.Errorf("expected PartiallySucceeded() to be false") | ||
} | ||
if !r.Failed() { | ||
t.Errorf("expected Failed() to be true") | ||
} | ||
if r.HasValue() { | ||
t.Errorf("expected HasValue() to be false") | ||
} | ||
if !r.HasError() { | ||
t.Errorf("expected HasError() to be true") | ||
} | ||
if r.Error().GetOrZero().Error() != "error" { | ||
t.Errorf("expected Error() to return error") | ||
} | ||
if r.Value().Present() { | ||
t.Errorf("expected Value() to be empty") | ||
} | ||
if r.String() != "Failure(error)" { | ||
t.Errorf("expected String() to return Failure(error)") | ||
} | ||
} | ||
|
||
func TestOfPartialSuccess(t *testing.T) { | ||
r := OfPartialSuccess(42, errors.New("error")) | ||
if r.Succeeded() { | ||
t.Errorf("expected Succeeded() to be false") | ||
} | ||
if !r.PartiallySucceeded() { | ||
t.Errorf("expected PartiallySucceeded() to be true") | ||
} | ||
if r.Failed() { | ||
t.Errorf("expected Failed() to be false") | ||
} | ||
if !r.HasValue() { | ||
t.Errorf("expected HasValue() to be true") | ||
} | ||
if !r.HasError() { | ||
t.Errorf("expected HasError() to be true") | ||
} | ||
if r.Value().GetOrZero() != 42 { | ||
t.Errorf("expected Value() to return 42") | ||
} | ||
if !r.Error().Present() { | ||
t.Errorf("expected Error() to be non-empty") | ||
} | ||
if r.String() != "PartialSuccess(42, error)" { | ||
t.Errorf("expected String() to return PartialSuccess(42, error)") | ||
} | ||
} | ||
|
||
func TestOf(t *testing.T) { | ||
t.Run("Success", func(t *testing.T) { | ||
r := Of(42, nil) | ||
if !r.Succeeded() { | ||
t.Errorf("expected Succeeded() to be true") | ||
} | ||
if r.PartiallySucceeded() { | ||
t.Errorf("expected PartiallySucceeded() to be false") | ||
} | ||
if r.Failed() { | ||
t.Errorf("expected Failed() to be false") | ||
} | ||
if !r.HasValue() { | ||
t.Errorf("expected HasValue() to be true") | ||
} | ||
if r.HasError() { | ||
t.Errorf("expected HasError() to be false") | ||
} | ||
if r.Value().GetOrZero() != 42 { | ||
t.Errorf("expected Value() to return 42") | ||
} | ||
if r.Error().Present() { | ||
t.Errorf("expected Error() to be empty") | ||
} | ||
if r.String() != "Success(42)" { | ||
t.Errorf("expected String() to return Success(42)") | ||
} | ||
}) | ||
|
||
t.Run("Failure", func(t *testing.T) { | ||
r := Of(42, errors.New("error")) | ||
if r.Succeeded() { | ||
t.Errorf("expected Succeeded() to be false") | ||
} | ||
if r.PartiallySucceeded() { | ||
t.Errorf("expected PartiallySucceeded() to be false") | ||
} | ||
if !r.Failed() { | ||
t.Errorf("expected Failed() to be true") | ||
} | ||
if r.HasValue() { | ||
t.Errorf("expected HasValue() to be false") | ||
} | ||
if !r.HasError() { | ||
t.Errorf("expected HasError() to be true") | ||
} | ||
if r.Error().GetOrZero().Error() != "error" { | ||
t.Errorf("expected Error() to return error") | ||
} | ||
if r.Value().Present() { | ||
t.Errorf("expected Value() to be empty") | ||
} | ||
if r.String() != "Failure(error)" { | ||
t.Errorf("expected String() to return Failure(error)") | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package res | ||
|
||
import ( | ||
"fmt" | ||
"github.com/jpfourny/papaya/pkg/opt" | ||
) | ||
|
||
// Success represents a successful result. | ||
// A successful result has a value and no error. | ||
type Success[T any] struct { | ||
Val T | ||
} | ||
|
||
// Assert that Success[T] implements Result[T] | ||
var _ Result[any] = Success[any]{} | ||
|
||
func (r Success[T]) Succeeded() bool { | ||
return true | ||
} | ||
|
||
func (r Success[T]) PartiallySucceeded() bool { | ||
return false | ||
} | ||
|
||
func (r Success[T]) Failed() bool { | ||
return false | ||
} | ||
|
||
func (r Success[T]) HasError() bool { | ||
return false | ||
} | ||
|
||
func (r Success[T]) HasValue() bool { | ||
return true | ||
} | ||
|
||
func (r Success[T]) Value() opt.Optional[T] { | ||
return opt.Of(r.Val) | ||
} | ||
|
||
func (r Success[T]) Error() opt.Optional[error] { | ||
return opt.Empty[error]() | ||
} | ||
|
||
func (r Success[T]) String() string { | ||
return fmt.Sprintf("Success(%#v)", r.Val) | ||
} |