Skip to content

Commit f16b5fd

Browse files
mikearnaldieffect-bot
authored andcommitted
Add Layer.updateService mirroring Effect.updateService (#4421)
1 parent ea8beed commit f16b5fd

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

.changeset/polite-tables-cry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": minor
3+
---
4+
5+
Add Layer.updateService mirroring Effect.updateService

packages/effect/src/Layer.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import * as Context from "./Context.js"
2424
import type * as Effect from "./Effect.js"
2525
import type * as Exit from "./Exit.js"
2626
import type { FiberRef } from "./FiberRef.js"
27-
import type { LazyArg } from "./Function.js"
27+
import { dual, type LazyArg } from "./Function.js"
2828
import { clockTag } from "./internal/clock.js"
2929
import * as core from "./internal/core.js"
3030
import * as defaultServices from "./internal/defaultServices.js"
@@ -1099,3 +1099,37 @@ export const buildWithMemoMap: {
10991099
scope: Scope.Scope
11001100
): Effect.Effect<Context.Context<ROut>, E, RIn>
11011101
} = internal.buildWithMemoMap
1102+
1103+
/**
1104+
* Updates a service in the context with a new implementation.
1105+
*
1106+
* **Details**
1107+
*
1108+
* This function modifies the existing implementation of a service in the
1109+
* context. It retrieves the current service, applies the provided
1110+
* transformation function `f`, and replaces the old service with the
1111+
* transformed one.
1112+
*
1113+
* **When to Use**
1114+
*
1115+
* This is useful for adapting or extending a service's behavior during the
1116+
* creation of a layer.
1117+
*
1118+
* @since 3.13.0
1119+
* @category utils
1120+
*/
1121+
export const updateService = dual<
1122+
<I, A>(
1123+
tag: Context.Tag<I, A>,
1124+
f: (a: A) => A
1125+
) => <A1, E1, R1>(layer: Layer<A1, E1, R1>) => Layer<A1, E1, I | R1>,
1126+
<A1, E1, R1, I, A>(
1127+
layer: Layer<A1, E1, R1>,
1128+
tag: Context.Tag<I, A>,
1129+
f: (a: A) => A
1130+
) => Layer<A1, E1, I | R1>
1131+
>(3, (layer, tag, f) =>
1132+
provide(
1133+
layer,
1134+
map(context(), (c) => Context.add(c, tag, f(Context.unsafeGet(c, tag))))
1135+
))

packages/effect/test/Layer.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,19 @@ describe("Layer", () => {
663663
strictEqual(result.bar, "bar: 1")
664664
}))
665665

666+
it.effect("Updates service via updateService", () =>
667+
Effect.gen(function*() {
668+
const Foo = Context.GenericTag<"Foo", string>("Foo")
669+
const FooDefault = Layer.succeed(Foo, "Foo")
670+
const Bar = Context.GenericTag<"Bar", string>("Bar")
671+
const BarDefault = Layer.effect(Bar, Foo).pipe(
672+
Layer.updateService(Foo, (x) => `Bar: ${x}`),
673+
Layer.provide(FooDefault)
674+
)
675+
const result = yield* Bar.pipe(Effect.provide(BarDefault))
676+
deepStrictEqual(result, "Bar: Foo")
677+
}))
678+
666679
describe("MemoMap", () => {
667680
it.effect("memoizes layer across builds", () =>
668681
Effect.gen(function*() {

0 commit comments

Comments
 (0)