Skip to content

Commit 4e44c6a

Browse files
authored
docs: update README and docs with complete operator coverage (#45)
1 parent 3c3ca4d commit 4e44c6a

5 files changed

Lines changed: 91 additions & 11 deletions

File tree

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ Extensions for interoperability with Arrow's `Either` type:
3838
- **Conversion** - `toAsyncResult()` to convert `Either` to `AsyncResult`
3939
- **Binding** - `bind()` to flatten `AsyncResult<Either<L, R>>` to `AsyncResult<R>`
4040
- **Flow conversion** - `asAsyncResult()` to convert `Flow<Either<L, R>>` to `Flow<AsyncResult<R>>`, `toEither()` to convert `Flow<AsyncResult<T>>` to `Either`
41+
- **Arrow Raise** - `Raise<Error>.bind()` to use `AsyncResult` inside Arrow's `either { }` / `result { }` blocks
4142

4243
### asyncresult-test
4344

4445
Testing utilities built on [assertk](https://github.com/willowtreeapps/assertk):
4546

4647
- **State assertions** - `isNotStarted()`, `isLoading()`, `isIncomplete()`, `isSuccess()`, `isError()`
4748
- **Value assertions** - `isSuccessEqualTo()`, `isErrorWithMetadata()`, `isErrorWithMetadataEqualTo()`
48-
- **Flow assertions** - `assertSuccess()`, `assertError()` for testing flow emissions
49+
- **Error assertions** - `isErrorWithThrowable()`, `isErrorWithThrowableOfType()`, `isErrorWithThrowableMessage()`, `isErrorWithId()`, `isErrorWithIdEqualTo()`, `hasErrorId()`
50+
- **Flow assertions** - `assertSuccess()`, `assertError()`, `assertErrorWithMetadata()`, `assertErrorWithId()`, `assertFirstIsLoading()`, `assertFirstIsNotStarted()`, `assertFirstIsIncomplete()`
51+
- **Collection assertions** - `hasAnyLoading()`, `hasAnyIncomplete()`, `allErrors()`, `allErrorMetadata()`
4952

5053
## Usage
5154

docs/core.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ val error = Error(
2727
metadata = NetworkFailure("timeout"),
2828
errorId = ErrorId("req-123")
2929
)
30+
31+
// Compose errors with the + operator
32+
val error = Error(IOException()) + NetworkFailure("timeout") // adds metadata
33+
val error = Error(IOException()) + ErrorId("req-123") // adds error ID
3034
```
3135

3236
## Checking state
@@ -317,14 +321,21 @@ val combined = userResult.zipWith(permissionsResult) { user, permissions ->
317321

318322
Supports up to 4 results.
319323

320-
### Spreading
324+
### Spreading and destructuring
321325

322326
Split a result containing a `Pair` or `Triple`:
323327

324328
```kotlin
325329
val (userResult, settingsResult) = pairResult.spread()
326330
```
327331

332+
You can also destructure directly without calling `spread()`:
333+
334+
```kotlin
335+
val (first, second) = pairResult // component1(), component2()
336+
val (a, b, c) = tripleResult // component1(), component2(), component3()
337+
```
338+
328339
### Combining collections
329340

330341
Convert a list of results into a result of a list:

docs/either.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,18 @@ val either: Either<NetworkError, User> = flow.toEither { error ->
128128
```
129129

130130
By default, it attempts to extract the error type from the `Error.metadata`.
131+
132+
## Arrow Raise integration
133+
134+
Use `AsyncResult` inside Arrow's `Raise` context (e.g., `either { }` or `result { }` blocks):
135+
136+
```kotlin
137+
import io.nlopez.asyncresult.either.bind
138+
139+
val either: Either<Error, User> = either {
140+
val user = fetchUser().bind() // extracts Success or raises Error
141+
user
142+
}
143+
```
144+
145+
The `Raise<Error>.bind()` extension extracts the value from `Success`, or raises (`shift`) the `Error` for non-success states (`Loading` and `NotStarted` raise `Error.Empty`).

docs/index.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ The library provides a rich set of operators for transforming, combining, and ex
3333

3434
The core module contains the type hierarchy and all essential utilities:
3535

36-
- **Transformations** - `mapSuccess`, `mapError`, `flatMap`, `bimap`, `fold`, `orError`, `filterOrError`, `castOrError`, `flatten`
37-
- **Monad comprehension DSL** - `result { }`, `bind()`, `ensure()`, `ensureNotNull()`, `error()`, `loading()`
38-
- **Value extraction** - `getOrNull`, `getOrDefault`, `getOrElse`, `getOrThrow`, `getOrEmpty`
39-
- **Side effects** - `onSuccess`, `onLoading`, `onError`, `onNotStarted`
40-
- **Unwrapping** - `unwrap`, `unwrapError`, `expect`, `expectError` (Rust-style extraction)
36+
- **Transformations** - `mapSuccess`, `mapError`, `flatMap`, `flatten`, `bimap`, `fold`, `orError`, `filterOrError`, `castOrError`
37+
- **State checks** - `isSuccess`, `isError`, `isIncomplete`, `isSuccessAnd`, `isErrorAnd`, `isErrorWithMetadataAnd`, `contains`
38+
- **Value extraction** - `getOrNull`, `getOrDefault`, `getOrElse`, `getOrThrow`, `getOrEmpty`, `errorOrNull`, `errorWithMetadataOrNull`, `throwableOrNull`, `errorIdOrNull`
39+
- **Side effects** - `onSuccess`, `onLoading`, `onError`, `onErrorWithMetadata`, `onNotStarted`, `onIncomplete`
40+
- **Unwrapping** - `unwrap`, `unwrapError`, `unwrapThrowable`, `unwrapMetadata`, `unwrapErrorId`, `expect`, `expectError`, `expectThrowable`, `expectMetadata`, `expectErrorId` (Rust-style extraction)
4141
- **Combining** - `zip`, `zipWith`, `and`, `andThen`, `spread`, `combine`, `sequence`
4242
- **Recovery** - `recover`, `recoverIf`, `or`, `orElse`
4343
- **Validation** - `toErrorIf`, `toErrorUnless`
44-
- **Flow helpers** - `asAsyncResult`, `onLoading`, `onSuccess`, `onError`, `skipWhileLoading`, `cacheLatestSuccess`, `timeoutToError`, `retryOnError`, `retryOnErrorWithMetadata`
45-
- **Collection utilities** - `errors`, `successes`, `throwables`, `incompletes`, `metadata`, `errorsFrom`, `anyError`, `anyLoading`, `anyIncomplete`
44+
- **Monad DSL** - `result { }` comprehension with `bind()`, `error()`, `loading()`, `ensure()`, `ensureNotNull()`
45+
- **Flow helpers** - `asAsyncResult`, `onLoading`, `onSuccess`, `onError`, `onIncomplete`, `skipWhileLoading`, `filterNotLoading`, `cacheLatestSuccess`, `timeoutToError`, `retryOnError`, `retryOnErrorWithMetadata`, `getOrThrow`, `getOrNull`, `getOrElse`
46+
- **Collection utilities** - `errors`, `successes`, `throwables`, `incompletes`, `metadata`, `anyLoading`, `anyIncomplete`, `anyError`, `errorsFrom`, `combine`, `sequence`, `partition`
4647

4748
[View full documentation](core.md)
4849

@@ -53,6 +54,7 @@ Extensions for interoperability with Arrow's `Either` type:
5354
- **Conversion** - `toAsyncResult()` to convert `Either` to `AsyncResult`
5455
- **Binding** - `bind()` to flatten `AsyncResult<Either<L, R>>` to `AsyncResult<R>`
5556
- **Flow conversion** - `asAsyncResult()` to convert `Flow<Either<L, R>>` to `Flow<AsyncResult<R>>`, `toEither()` to convert `Flow<AsyncResult<T>>` to `Either`
57+
- **Arrow Raise** - `Raise<Error>.bind()` to use `AsyncResult` inside Arrow's `either { }` / `result { }` blocks
5658

5759
[View full documentation](either.md)
5860

@@ -62,7 +64,9 @@ Testing utilities built on [assertk](https://github.com/willowtreeapps/assertk):
6264

6365
- **State assertions** - `isNotStarted()`, `isLoading()`, `isIncomplete()`, `isSuccess()`, `isError()`
6466
- **Value assertions** - `isSuccessEqualTo()`, `isErrorWithMetadata()`, `isErrorWithMetadataEqualTo()`
65-
- **Flow assertions** - `assertSuccess()`, `assertError()` for testing flow emissions
67+
- **Error assertions** - `isErrorWithThrowable()`, `isErrorWithThrowableOfType()`, `isErrorWithThrowableMessage()`, `isErrorWithId()`, `isErrorWithIdEqualTo()`, `hasErrorId()`
68+
- **Flow assertions** - `assertSuccess()`, `assertError()`, `assertErrorWithMetadata()`, `assertErrorWithId()`, `assertFirstIsLoading()`, `assertFirstIsNotStarted()`, `assertFirstIsIncomplete()`
69+
- **Collection assertions** - `hasAnyLoading()`, `hasAnyIncomplete()`, `allErrors()`, `allErrorMetadata()`
6670

6771
[View full documentation](testing.md)
6872

docs/testing.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,25 @@ assertThat(result).isError()
4343
// Check the throwable
4444
assertThat(result).isError().isThrowableEqualTo(expectedException)
4545

46+
// Check throwable type
47+
assertThat(result).isErrorWithThrowable() // asserts Error has a non-null throwable
48+
assertThat(result).isErrorWithThrowableOfType<IOException>() // asserts throwable is specific type
49+
assertThat(result).isErrorWithThrowableMessage("Network error") // asserts throwable message
50+
4651
// Check metadata
4752
assertThat(result).isErrorWithMetadata<T, NetworkError>()
4853
assertThat(result).isErrorWithMetadataEqualTo(NetworkError.Timeout)
4954

5055
// Chain assertions on metadata
5156
assertThat(result).isError().isMetadataEqualTo(expectedMetadata)
57+
58+
// Check error ID
59+
assertThat(result).isErrorWithId() // asserts Error has a non-null errorId
60+
assertThat(result).isErrorWithIdEqualTo(ErrorId("req-123"))
61+
assertThat(result).hasErrorId(ErrorId("req-123"))
62+
63+
// Chain assertions on error ID
64+
assertThat(result).isError().isErrorIdEqualTo(ErrorId("req-123"))
5265
```
5366

5467
## Flow assertions
@@ -62,6 +75,40 @@ flow.assertSuccess(42)
6275
// Assert the first terminal emission is Error and get it for further checks
6376
val error: Error = flow.assertError()
6477
assertThat(error.throwable).isInstanceOf(IOException::class)
78+
79+
// Assert error with typed metadata
80+
val metadata: NetworkError = flow.assertErrorWithMetadata<NetworkError>()
81+
82+
// Assert error with throwable type
83+
flow.assertErrorWithThrowableOfType<IOException>()
84+
85+
// Assert error with error ID
86+
flow.assertErrorWithId(ErrorId("req-123"))
87+
```
88+
89+
### Initial state assertions
90+
91+
Assert the very first emission (before terminal state):
92+
93+
```kotlin
94+
flow.assertFirstIsLoading()
95+
flow.assertFirstIsNotStarted()
96+
flow.assertFirstIsIncomplete() // Loading or NotStarted
6597
```
6698

67-
These suspend functions wait for the first `Success` or `Error` emission, ignoring `Loading` and `NotStarted` states.
99+
## Collection assertions
100+
101+
Assert properties of a collection of results:
102+
103+
```kotlin
104+
val results: List<AsyncResult<Int>> = listOf(Loading, Success(1), Error.Empty)
105+
106+
assertThat(results).hasAnyLoading()
107+
assertThat(results).hasAnyIncomplete()
108+
109+
// Extract and assert on all errors
110+
assertThat(results).allErrors().hasSize(1)
111+
112+
// Extract and assert on all error metadata of a specific type
113+
assertThat(results).allErrorMetadata<NetworkError>().isEmpty()
114+
```

0 commit comments

Comments
 (0)