Skip to content

Commit

Permalink
make serviceFunctions accept an Effect (#1797)
Browse files Browse the repository at this point in the history
  • Loading branch information
matheuspuel authored Jan 1, 2024
1 parent 6299b84 commit 7b5eaa3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-zoos-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

make serviceFunctions and similar accept an Effect as the service
36 changes: 19 additions & 17 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3154,56 +3154,58 @@ export const provideServiceEffect: {
* @since 2.0.0
* @category context
*/
export const serviceFunction: <T extends Context.Tag<any, any>, Args extends Array<any>, A>(
service: T,
f: (_: Context.Tag.Service<T>) => (...args: Args) => A
) => (...args: Args) => Effect<Context.Tag.Identifier<T>, never, A> = effect.serviceFunction
export const serviceFunction: <T extends Effect<any, any, any>, Args extends Array<any>, A>(
getService: T,
f: (_: Effect.Success<T>) => (...args: Args) => A
) => (...args: Args) => Effect<Effect.Context<T>, Effect.Error<T>, A> = effect.serviceFunction

/**
* @since 2.0.0
* @category context
*/
export const serviceFunctionEffect: <T extends Context.Tag<any, any>, Args extends Array<any>, R, E, A>(
service: T,
f: (_: Context.Tag.Service<T>) => (...args: Args) => Effect<R, E, A>
) => (...args: Args) => Effect<R | Context.Tag.Identifier<T>, E, A> = effect.serviceFunctionEffect
export const serviceFunctionEffect: <T extends Effect<any, any, any>, Args extends Array<any>, R, E, A>(
getService: T,
f: (_: Effect.Success<T>) => (...args: Args) => Effect<R, E, A>
) => (...args: Args) => Effect<R | Effect.Context<T>, E | Effect.Error<T>, A> = effect.serviceFunctionEffect

/**
* @since 2.0.0
* @category context
*/
export const serviceFunctions: <I, S>(
tag: Context.Tag<I, S>
export const serviceFunctions: <SR, SE, S>(
getService: Effect<SR, SE, S>
) => {
[k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never }[keyof S]]:
S[k] extends (...args: infer Args) => Effect<infer R, infer E, infer A> ? (...args: Args) => Effect<R | I, E, A> :
S[k] extends (...args: infer Args) => Effect<infer R, infer E, infer A> ?
(...args: Args) => Effect<R | SR, E | SE, A> :
never
} = effect.serviceFunctions

/**
* @since 2.0.0
* @category context
*/
export const serviceConstants: <I, S>(
tag: Context.Tag<I, S>
export const serviceConstants: <SR, SE, S>(
getService: Effect<SR, SE, S>
) => {
[k in { [k in keyof S]: S[k] extends Effect<any, any, any> ? k : never }[keyof S]]: S[k] extends
Effect<infer R, infer E, infer A> ? Effect<R | I, E, A> : never
Effect<infer R, infer E, infer A> ? Effect<R | SR, E | SE, A> : never
} = effect.serviceConstants

/**
* @since 2.0.0
* @category context
*/
export const serviceMembers: <I, S>(tag: Context.Tag<I, S>) => {
export const serviceMembers: <SR, SE, S>(getService: Effect<SR, SE, S>) => {
functions: {
[k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect<any, any, any> ? k : never }[keyof S]]:
S[k] extends (...args: infer Args) => Effect<infer R, infer E, infer A> ? (...args: Args) => Effect<R | I, E, A> :
S[k] extends (...args: infer Args) => Effect<infer R, infer E, infer A> ?
(...args: Args) => Effect<R | SR, E | SE, A> :
never
}
constants: {
[k in { [k in keyof S]: S[k] extends Effect<any, any, any> ? k : never }[keyof S]]: S[k] extends
Effect<infer R, infer E, infer A> ? Effect<R | I, E, A> : never
Effect<infer R, infer E, infer A> ? Effect<R | SR, E | SE, A> : never
}
} = effect.serviceMembers

Expand Down
44 changes: 23 additions & 21 deletions packages/effect/src/internal/core-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1832,62 +1832,64 @@ export const withMetric = dual<
>(2, (self, metric) => metric(self))

/** @internal */
export const serviceFunctionEffect = <T extends Context.Tag<any, any>, Args extends Array<any>, R, E, A>(
service: T,
f: (_: Context.Tag.Service<T>) => (...args: Args) => Effect.Effect<R, E, A>
export const serviceFunctionEffect = <T extends Effect.Effect<any, any, any>, Args extends Array<any>, R, E, A>(
getService: T,
f: (_: Effect.Effect.Success<T>) => (...args: Args) => Effect.Effect<R, E, A>
) =>
(...args: Args): Effect.Effect<R | Context.Tag.Identifier<T>, E, A> => core.flatMap(service, (a) => f(a)(...args))
(...args: Args): Effect.Effect<R | Effect.Effect.Context<T>, E | Effect.Effect.Error<T>, A> =>
core.flatMap(getService, (a) => f(a)(...args))

/** @internal */
export const serviceFunction = <T extends Context.Tag<any, any>, Args extends Array<any>, A>(
service: T,
f: (_: Context.Tag.Service<T>) => (...args: Args) => A
export const serviceFunction = <T extends Effect.Effect<any, any, any>, Args extends Array<any>, A>(
getService: T,
f: (_: Effect.Effect.Success<T>) => (...args: Args) => A
) =>
(...args: Args): Effect.Effect<Context.Tag.Identifier<T>, never, A> => core.map(service, (a) => f(a)(...args))
(...args: Args): Effect.Effect<Effect.Effect.Context<T>, Effect.Effect.Error<T>, A> =>
core.map(getService, (a) => f(a)(...args))

/** @internal */
export const serviceFunctions = <I, S>(
tag: Context.Tag<I, S>
export const serviceFunctions = <SR, SE, S>(
getService: Effect.Effect<SR, SE, S>
): {
[k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never }[keyof S]]:
S[k] extends (...args: infer Args) => Effect.Effect<infer R, infer E, infer A>
? (...args: Args) => Effect.Effect<R | I, E, A>
? (...args: Args) => Effect.Effect<R | SR, E | SE, A>
: never
} =>
new Proxy({} as any, {
get(_target: any, prop: any, _receiver) {
return (...args: Array<any>) => core.flatMap(tag, (s: any) => s[prop](...args))
return (...args: Array<any>) => core.flatMap(getService, (s: any) => s[prop](...args))
}
})

/** @internal */
export const serviceConstants = <I, S>(
tag: Context.Tag<I, S>
export const serviceConstants = <SR, SE, S>(
getService: Effect.Effect<SR, SE, S>
): {
[k in { [k in keyof S]: S[k] extends Effect.Effect<any, any, any> ? k : never }[keyof S]]: S[k] extends
Effect.Effect<infer R, infer E, infer A> ? Effect.Effect<R | I, E, A> : never
Effect.Effect<infer R, infer E, infer A> ? Effect.Effect<R | SR, E | SE, A> : never
} =>
new Proxy({} as any, {
get(_target: any, prop: any, _receiver) {
return core.flatMap(tag, (s: any) => s[prop])
return core.flatMap(getService, (s: any) => s[prop])
}
})

/** @internal */
export const serviceMembers = <I, S>(tag: Context.Tag<I, S>): {
export const serviceMembers = <SR, SE, S>(getService: Effect.Effect<SR, SE, S>): {
functions: {
[k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never }[keyof S]]:
S[k] extends (...args: infer Args) => Effect.Effect<infer R, infer E, infer A>
? (...args: Args) => Effect.Effect<R | I, E, A>
? (...args: Args) => Effect.Effect<R | SR, E | SE, A>
: never
}
constants: {
[k in { [k in keyof S]: S[k] extends Effect.Effect<any, any, any> ? k : never }[keyof S]]: S[k] extends
Effect.Effect<infer R, infer E, infer A> ? Effect.Effect<R | I, E, A> : never
Effect.Effect<infer R, infer E, infer A> ? Effect.Effect<R | SR, E | SE, A> : never
}
} => ({
functions: serviceFunctions(tag),
constants: serviceConstants(tag)
functions: serviceFunctions(getService),
constants: serviceConstants(getService)
})

/** @internal */
Expand Down

0 comments on commit 7b5eaa3

Please sign in to comment.