Skip to content

Commit

Permalink
Add Layer.updateService mirroring Effect.updateService (#4421)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikearnaldi authored and effect-bot committed Feb 10, 2025
1 parent 198adbd commit 787fed5
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/polite-tables-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Add Layer.updateService mirroring Effect.updateService
36 changes: 35 additions & 1 deletion packages/effect/src/Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import * as Context from "./Context.js"
import type * as Effect from "./Effect.js"
import type * as Exit from "./Exit.js"
import type { FiberRef } from "./FiberRef.js"
import type { LazyArg } from "./Function.js"
import { dual, type LazyArg } from "./Function.js"
import { clockTag } from "./internal/clock.js"
import * as core from "./internal/core.js"
import * as defaultServices from "./internal/defaultServices.js"
Expand Down Expand Up @@ -1118,3 +1118,37 @@ export const buildWithMemoMap: {
scope: Scope.Scope
): Effect.Effect<Context.Context<ROut>, E, RIn>
} = internal.buildWithMemoMap

/**
* Updates a service in the context with a new implementation.
*
* **Details**
*
* This function modifies the existing implementation of a service in the
* context. It retrieves the current service, applies the provided
* transformation function `f`, and replaces the old service with the
* transformed one.
*
* **When to Use**
*
* This is useful for adapting or extending a service's behavior during the
* creation of a layer.
*
* @since 3.13.0
* @category utils
*/
export const updateService = dual<
<I, A>(
tag: Context.Tag<I, A>,
f: (a: A) => A
) => <A1, E1, R1>(layer: Layer<A1, E1, R1>) => Layer<A1, E1, I | R1>,
<A1, E1, R1, I, A>(
layer: Layer<A1, E1, R1>,
tag: Context.Tag<I, A>,
f: (a: A) => A
) => Layer<A1, E1, I | R1>
>(3, (layer, tag, f) =>
provide(
layer,
map(context(), (c) => Context.add(c, tag, f(Context.unsafeGet(c, tag))))
))
13 changes: 13 additions & 0 deletions packages/effect/test/Layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,19 @@ describe("Layer", () => {
strictEqual(result.bar, "bar: 1")
}))

it.effect("Updates service via updateService", () =>
Effect.gen(function*() {
const Foo = Context.GenericTag<"Foo", string>("Foo")
const FooDefault = Layer.succeed(Foo, "Foo")
const Bar = Context.GenericTag<"Bar", string>("Bar")
const BarDefault = Layer.effect(Bar, Foo).pipe(
Layer.updateService(Foo, (x) => `Bar: ${x}`),
Layer.provide(FooDefault)
)
const result = yield* Bar.pipe(Effect.provide(BarDefault))
deepStrictEqual(result, "Bar: Foo")
}))

describe("MemoMap", () => {
it.effect("memoizes layer across builds", () =>
Effect.gen(function*() {
Expand Down

0 comments on commit 787fed5

Please sign in to comment.