Skip to content

Commit

Permalink
add RequestResolver.aroundRequests api (#2145)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart authored Feb 14, 2024
1 parent c568645 commit b1163b2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .changeset/early-games-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"effect": patch
---

add RequestResolver.aroundRequests api

This can be used to run side effects that introspect the requests being
executed.

Example:

```ts
import { Effect, Request, RequestResolver } from "effect";

interface GetUserById extends Request.Request<unknown> {
readonly id: number;
}

declare const resolver: RequestResolver.RequestResolver<GetUserById>;

RequestResolver.aroundRequests(
resolver,
(requests) => Effect.log(`got ${requests.length} requests`),
(requests, _) => Effect.log(`finised running ${requests.length} requests`),
);
```
37 changes: 37 additions & 0 deletions packages/effect/src/RequestResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,43 @@ export const around: {
): RequestResolver<A, R | R2 | R3>
} = internal.around

/**
* A data source aspect that executes requests between two effects, `before`
* and `after`, where the result of `before` can be used by `after`.
*
* The `before` and `after` effects are provided with the requests being executed.
*
* @since 2.0.0
* @category combinators
* @example
* import { Effect, Request, RequestResolver } from "effect"
*
* interface GetUserById extends Request.Request<unknown> {
* readonly id: number
* }
*
* const resolver = RequestResolver.fromFunction(
* (request: GetUserById) => ({ id: request.id, name: "John" })
* )
*
* RequestResolver.aroundRequests(
* resolver,
* (requests) => Effect.log(`got ${requests.length} requests`),
* (requests, _) => Effect.log(`finised running ${requests.length} requests`)
* )
*/
export const aroundRequests: {
<A, R2, A2, R3, _>(
before: (requests: ReadonlyArray<Types.NoInfer<A>>) => Effect.Effect<A2, never, R2>,
after: (requests: ReadonlyArray<Types.NoInfer<A>>, _: A2) => Effect.Effect<_, never, R3>
): <R>(self: RequestResolver<A, R>) => RequestResolver<A, R2 | R3 | R>
<R, A, R2, A2, R3, _>(
self: RequestResolver<A, R>,
before: (requests: ReadonlyArray<Types.NoInfer<A>>) => Effect.Effect<A2, never, R2>,
after: (requests: ReadonlyArray<Types.NoInfer<A>>, _: A2) => Effect.Effect<_, never, R3>
): RequestResolver<A, R | R2 | R3>
} = internal.aroundRequests

/**
* Returns a data source that executes at most `n` requests in parallel.
*
Expand Down
27 changes: 27 additions & 0 deletions packages/effect/src/internal/dataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { dual, pipe } from "../Function.js"
import * as RA from "../ReadonlyArray.js"
import type * as Request from "../Request.js"
import type * as RequestResolver from "../RequestResolver.js"
import type { NoInfer } from "../Types.js"
import * as core from "./core.js"
import { invokeWithInterrupt, zipWithOptions } from "./fiberRuntime.js"
import { complete } from "./request.js"
Expand Down Expand Up @@ -71,6 +72,32 @@ export const around = dual<
Chunk.make("Around", self, before, after)
))

/** @internal */
export const aroundRequests = dual<
<A, R2, A2, R3, _>(
before: (requests: ReadonlyArray<NoInfer<A>>) => Effect.Effect<A2, never, R2>,
after: (requests: ReadonlyArray<NoInfer<A>>, _: A2) => Effect.Effect<_, never, R3>
) => <R>(
self: RequestResolver.RequestResolver<A, R>
) => RequestResolver.RequestResolver<A, R | R2 | R3>,
<R, A, R2, A2, R3, _>(
self: RequestResolver.RequestResolver<A, R>,
before: (requests: ReadonlyArray<NoInfer<A>>) => Effect.Effect<A2, never, R2>,
after: (requests: ReadonlyArray<NoInfer<A>>, _: A2) => Effect.Effect<_, never, R3>
) => RequestResolver.RequestResolver<A, R | R2 | R3>
>(3, (self, before, after) =>
new core.RequestResolverImpl(
(requests) => {
const flatRequests = requests.flatMap((chunk) => chunk.map((entry) => entry.request))
return core.acquireUseRelease(
before(flatRequests),
() => self.runAll(requests),
(a2) => after(flatRequests, a2)
)
},
Chunk.make("AroundRequests", self, before, after)
))

/** @internal */
export const batchN = dual<
(n: number) => <R, A>(
Expand Down

0 comments on commit b1163b2

Please sign in to comment.