/** * @since 2.0.0 */ import type { NonEmptyArray } from "./Array.js" import * as Context from "./Context.js" import * as Effect from "./Effect.js" import type * as Either from "./Either.js" import type * as Equal from "./Equal.js" import type { FiberRef } from "./FiberRef.js" import * as core from "./internal/core.js" import * as internal from "./internal/dataSource.js" import type { Pipeable } from "./Pipeable.js" import type * as Request from "./Request.js" import type * as Types from "./Types.js" /** * @since 2.0.0 * @category symbols */ export const RequestResolverTypeId: unique symbol = core.RequestResolverTypeId /** * @since 2.0.0 * @category symbols */ export type RequestResolverTypeId = typeof RequestResolverTypeId /** * The `RequestResolver` interface requires an environment `R` and handles * the execution of requests of type `A`. * * Implementations must provide a `runAll` method, which processes a collection * of requests and produces an effect that fulfills these requests. Requests are * organized into a `Array>`, where the outer `Array` groups requests * into batches that are executed sequentially, and each inner `Array` contains * requests that can be executed in parallel. This structure allows * implementations to analyze all incoming requests collectively and optimize * query execution accordingly. * * Implementations are typically specialized for a subtype of `Request`. * However, they are not strictly limited to these subtypes as long as they can * map any given request type to `Request`. Implementations should inspect * the collection of requests to identify the needed information and execute the * corresponding queries. It is imperative that implementations resolve all the * requests they receive. Failing to do so will lead to a `QueryFailure` error * during query execution. * * @since 2.0.0 * @category models */ export interface RequestResolver extends RequestResolver.Variance, Equal.Equal, Pipeable { /** * Execute a collection of requests. The outer `Array` represents batches * of requests that must be performed sequentially. The inner `Array` * represents a batch of requests that can be performed in parallel. */ runAll(requests: Array>>): Effect.Effect /** * Identify the data source using the specific identifier */ identified(...identifiers: Array): RequestResolver } /** * @since 2.0.0 */ export declare namespace RequestResolver { /** * @since 2.0.0 * @category models */ export interface Variance { readonly [RequestResolverTypeId]: { readonly _A: Types.Contravariant readonly _R: Types.Covariant } } } /** * @since 2.0.0 * @category utils */ export const contextFromEffect = >(self: RequestResolver) => Effect.contextWith((_: Context.Context) => provideContext(self, _)) /** * @since 2.0.0 * @category utils */ export const contextFromServices = >>(...services: Services) => >( self: RequestResolver ): Effect.Effect< RequestResolver }[number]>>, never, { [k in keyof Services]: Effect.Effect.Context }[number] > => Effect.contextWith((_) => provideContext(self as any, Context.pick(...services)(_ as any))) /** * Returns `true` if the specified value is a `RequestResolver`, `false` otherwise. * * @since 2.0.0 * @category refinements */ export const isRequestResolver: (u: unknown) => u is RequestResolver = core.isRequestResolver /** * Constructs a data source with the specified identifier and method to run * requests. * * @since 2.0.0 * @category constructors */ export const make: ( runAll: (requests: Array>) => Effect.Effect ) => RequestResolver = internal.make /** * Constructs a data source with the specified identifier and method to run * requests. * * @since 2.0.0 * @category constructors */ export const makeWithEntry: ( runAll: (requests: Array>>) => Effect.Effect ) => RequestResolver = internal.makeWithEntry /** * Constructs a data source from a function taking a collection of requests. * * @since 2.0.0 * @category constructors */ export const makeBatched: , R>( run: (requests: NonEmptyArray) => Effect.Effect ) => RequestResolver = internal.makeBatched /** * A data source aspect that executes requests between two effects, `before` * and `after`, where the result of `before` can be used by `after`. * * @since 2.0.0 * @category combinators */ export const around: { /** * A data source aspect that executes requests between two effects, `before` * and `after`, where the result of `before` can be used by `after`. * * @since 2.0.0 * @category combinators */ ( before: Effect.Effect, after: (a: A2) => Effect.Effect ): (self: RequestResolver) => RequestResolver /** * A data source aspect that executes requests between two effects, `before` * and `after`, where the result of `before` can be used by `after`. * * @since 2.0.0 * @category combinators */ ( self: RequestResolver, before: Effect.Effect, after: (a: A2) => Effect.Effect ): RequestResolver } = 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 * ```ts * import { Effect, Request, RequestResolver } from "effect" * * interface GetUserById extends Request.Request { * 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 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 * ```ts * import { Effect, Request, RequestResolver } from "effect" * * interface GetUserById extends Request.Request { * 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`) * ) * ``` */ ( before: (requests: ReadonlyArray>) => Effect.Effect, after: (requests: ReadonlyArray>, _: A2) => Effect.Effect ): (self: RequestResolver) => RequestResolver /** * 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 * ```ts * import { Effect, Request, RequestResolver } from "effect" * * interface GetUserById extends Request.Request { * 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`) * ) * ``` */ ( self: RequestResolver, before: (requests: ReadonlyArray>) => Effect.Effect, after: (requests: ReadonlyArray>, _: A2) => Effect.Effect ): RequestResolver } = internal.aroundRequests /** * Returns a data source that executes at most `n` requests in parallel. * * @since 2.0.0 * @category combinators */ export const batchN: { /** * Returns a data source that executes at most `n` requests in parallel. * * @since 2.0.0 * @category combinators */ (n: number): (self: RequestResolver) => RequestResolver /** * Returns a data source that executes at most `n` requests in parallel. * * @since 2.0.0 * @category combinators */ (self: RequestResolver, n: number): RequestResolver } = internal.batchN /** * Provides this data source with part of its required context. * * @since 2.0.0 * @category context */ export const mapInputContext: { /** * Provides this data source with part of its required context. * * @since 2.0.0 * @category context */ (f: (context: Context.Context) => Context.Context): >(self: RequestResolver) => RequestResolver /** * Provides this data source with part of its required context. * * @since 2.0.0 * @category context */ , R0>( self: RequestResolver, f: (context: Context.Context) => Context.Context ): RequestResolver } = internal.mapInputContext /** * Returns a new data source that executes requests of type `C` using the * specified function to transform `C` requests into requests that either this * data source or that data source can execute. * * @since 2.0.0 * @category combinators */ export const eitherWith: { /** * Returns a new data source that executes requests of type `C` using the * specified function to transform `C` requests into requests that either this * data source or that data source can execute. * * @since 2.0.0 * @category combinators */ , R2, B extends Request.Request, C extends Request.Request>( that: RequestResolver, f: (_: Request.Entry) => Either.Either, Request.Entry> ): (self: RequestResolver) => RequestResolver /** * Returns a new data source that executes requests of type `C` using the * specified function to transform `C` requests into requests that either this * data source or that data source can execute. * * @since 2.0.0 * @category combinators */ < R, A extends Request.Request, R2, B extends Request.Request, C extends Request.Request >( self: RequestResolver, that: RequestResolver, f: (_: Request.Entry) => Either.Either, Request.Entry> ): RequestResolver } = internal.eitherWith /** * Constructs a data source from a pure function. * * @since 2.0.0 * @category constructors */ export const fromFunction: >( f: (request: A) => Request.Request.Success ) => RequestResolver = internal.fromFunction /** * Constructs a data source from a pure function that takes a list of requests * and returns a list of results of the same size. Each item in the result * list must correspond to the item at the same index in the request list. * * @since 2.0.0 * @category constructors */ export const fromFunctionBatched: >( f: (chunk: NonEmptyArray) => Iterable> ) => RequestResolver = internal.fromFunctionBatched /** * Constructs a data source from an effectual function. * * @since 2.0.0 * @category constructors */ export const fromEffect: >( f: (a: A) => Effect.Effect, Request.Request.Error, R> ) => RequestResolver = internal.fromEffect /** * Constructs a data source from a list of tags paired to functions, that takes * a list of requests and returns a list of results of the same size. Each item * in the result list must correspond to the item at the same index in the * request list. * * @since 2.0.0 * @category constructors */ export const fromEffectTagged: & { readonly _tag: string }>() => < Fns extends { readonly [Tag in A["_tag"]]: [Extract] extends [infer Req] ? Req extends Request.Request ? (requests: Array) => Effect.Effect, ReqE, any> : never : never } >( fns: Fns ) => RequestResolver extends Effect.Effect ? R : never> = internal.fromEffectTagged /** * A data source that never executes requests. * * @since 2.0.0 * @category constructors */ export const never: RequestResolver = internal.never /** * Provides this data source with its required context. * * @since 2.0.0 * @category context */ export const provideContext: { /** * Provides this data source with its required context. * * @since 2.0.0 * @category context */ (context: Context.Context): >(self: RequestResolver) => RequestResolver /** * Provides this data source with its required context. * * @since 2.0.0 * @category context */ >(self: RequestResolver, context: Context.Context): RequestResolver } = internal.provideContext /** * Returns a new data source that executes requests by sending them to this * data source and that data source, returning the results from the first data * source to complete and safely interrupting the loser. * * @since 2.0.0 * @category combinators */ export const race: { /** * Returns a new data source that executes requests by sending them to this * data source and that data source, returning the results from the first data * source to complete and safely interrupting the loser. * * @since 2.0.0 * @category combinators */ , R2>(that: RequestResolver): , R>(self: RequestResolver) => RequestResolver /** * Returns a new data source that executes requests by sending them to this * data source and that data source, returning the results from the first data * source to complete and safely interrupting the loser. * * @since 2.0.0 * @category combinators */ , R, A2 extends Request.Request, R2>(self: RequestResolver, that: RequestResolver): RequestResolver } = internal.race /** * Returns a new data source with a localized FiberRef * * @since 2.0.0 * @category combinators */ export const locally: { /** * Returns a new data source with a localized FiberRef * * @since 2.0.0 * @category combinators */ (self: FiberRef, value: A): >(use: RequestResolver) => RequestResolver /** * Returns a new data source with a localized FiberRef * * @since 2.0.0 * @category combinators */ , A>(use: RequestResolver, self: FiberRef, value: A): RequestResolver } = core.resolverLocally