@@ -126,12 +126,12 @@ yield* Lens.updateSomeEffect(lens, (value) =>
|
|||||||
Effect v4 removed its `Readable` and `Subscribable` modules. This package provides a small compatible abstraction with `get` and `changes` properties:
|
Effect v4 removed its `Readable` and `Subscribable` modules. This package provides a small compatible abstraction with `get` and `changes` properties:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { Subscribable } from "effect-lens-next"
|
import { Lens, Subscribable } from "effect-lens-next"
|
||||||
|
|
||||||
const users = Subscribable.fromSubscriptionRef(usersRef)
|
const users = Lens.fromSubscriptionRef(usersRef)
|
||||||
const count = Subscribable.focusArrayLength(users)
|
const count = Subscribable.focusArrayLength(users)
|
||||||
|
|
||||||
const current = yield* count.get
|
const current = yield* count.get
|
||||||
```
|
```
|
||||||
|
|
||||||
The module includes `make`, `map`, `mapEffect`, `unwrap`, `fromSubscriptionRef`, and the same readonly focus helpers used by Lens.
|
The module includes `make`, `map`, `mapEffect`, `unwrap`, and the same readonly focus helpers used by Lens. A `SubscriptionRef` can first be converted with `Lens.fromSubscriptionRef`, since every Lens is already a Subscribable.
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export declare namespace LensImpl {
|
|||||||
|
|
||||||
export abstract class LensImpl<in out A, in out ER = never, in out EW = never, in out RR = never, in out RW = never>
|
export abstract class LensImpl<in out A, in out ER = never, in out EW = never, in out RR = never, in out RW = never>
|
||||||
extends Pipeable.Class implements Lens<A, ER, EW, RR, RW> {
|
extends Pipeable.Class implements Lens<A, ER, EW, RR, RW> {
|
||||||
readonly [Subscribable.TypeId]: Subscribable.TypeId = Subscribable.TypeId
|
readonly [Subscribable.SubscribableTypeId]: Subscribable.SubscribableTypeId = Subscribable.SubscribableTypeId
|
||||||
readonly [LensTypeId]: LensTypeId = LensTypeId
|
readonly [LensTypeId]: LensTypeId = LensTypeId
|
||||||
readonly [LensImplTypeId]: LensImplTypeId = LensImplTypeId
|
readonly [LensImplTypeId]: LensImplTypeId = LensImplTypeId
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { Chunk, Effect, SubscriptionRef } from "effect"
|
import { Chunk, Effect, SubscriptionRef } from "effect"
|
||||||
|
import * as Lens from "./Lens.js"
|
||||||
import * as Subscribable from "./Subscribable.js"
|
import * as Subscribable from "./Subscribable.js"
|
||||||
|
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ describe("Subscribable", () => {
|
|||||||
Effect.flatMap(
|
Effect.flatMap(
|
||||||
SubscriptionRef.make([1, 2, 3]),
|
SubscriptionRef.make([1, 2, 3]),
|
||||||
parent => {
|
parent => {
|
||||||
const sizeSub = Subscribable.focusArrayLength(Subscribable.fromSubscriptionRef(parent))
|
const sizeSub = Subscribable.focusArrayLength(Lens.fromSubscriptionRef(parent))
|
||||||
return Effect.flatMap(
|
return Effect.flatMap(
|
||||||
sizeSub.get,
|
sizeSub.get,
|
||||||
initial => Effect.flatMap(
|
initial => Effect.flatMap(
|
||||||
@@ -29,7 +30,7 @@ describe("Subscribable", () => {
|
|||||||
Effect.flatMap(
|
Effect.flatMap(
|
||||||
SubscriptionRef.make(Chunk.make(1, 2) as Chunk.Chunk<number>),
|
SubscriptionRef.make(Chunk.make(1, 2) as Chunk.Chunk<number>),
|
||||||
parent => {
|
parent => {
|
||||||
const sizeSub = Subscribable.focusChunkSize(Subscribable.fromSubscriptionRef(parent))
|
const sizeSub = Subscribable.focusChunkSize(Lens.fromSubscriptionRef(parent))
|
||||||
return Effect.flatMap(
|
return Effect.flatMap(
|
||||||
sizeSub.get,
|
sizeSub.get,
|
||||||
initial => Effect.flatMap(
|
initial => Effect.flatMap(
|
||||||
@@ -49,7 +50,7 @@ describe("Subscribable", () => {
|
|||||||
Effect.flatMap(
|
Effect.flatMap(
|
||||||
SubscriptionRef.make([1, 2, 3]),
|
SubscriptionRef.make([1, 2, 3]),
|
||||||
parent => {
|
parent => {
|
||||||
const sizeSub = Subscribable.focusIterableSize(Subscribable.fromSubscriptionRef(parent))
|
const sizeSub = Subscribable.focusIterableSize(Lens.fromSubscriptionRef(parent))
|
||||||
return Effect.flatMap(
|
return Effect.flatMap(
|
||||||
sizeSub.get,
|
sizeSub.get,
|
||||||
initial => Effect.flatMap(
|
initial => Effect.flatMap(
|
||||||
|
|||||||
@@ -9,43 +9,68 @@ import {
|
|||||||
Pipeable,
|
Pipeable,
|
||||||
Predicate,
|
Predicate,
|
||||||
Stream,
|
Stream,
|
||||||
SubscriptionRef,
|
|
||||||
} from "effect"
|
} from "effect"
|
||||||
|
|
||||||
|
|
||||||
export const TypeId: unique symbol = Symbol.for("@effect-fc/Lens/v4/Subscribable")
|
export const SubscribableTypeId: unique symbol = Symbol.for("@effect-fc/Lens/v4/Subscribable")
|
||||||
export type TypeId = typeof TypeId
|
export type SubscribableTypeId = typeof SubscribableTypeId
|
||||||
|
|
||||||
export interface Subscribable<in out A, in out E = never, in out R = never> extends Pipeable.Pipeable {
|
export interface Subscribable<in out A, in out E = never, in out R = never> extends Pipeable.Pipeable {
|
||||||
readonly [TypeId]: TypeId
|
readonly [SubscribableTypeId]: SubscribableTypeId
|
||||||
readonly get: Effect.Effect<A, E, R>
|
readonly get: Effect.Effect<A, E, R>
|
||||||
readonly changes: Stream.Stream<A, E, R>
|
readonly changes: Stream.Stream<A, E, R>
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscribableImpl<in out A, in out E, in out R>
|
export const isSubscribable = (u: unknown): u is Subscribable<unknown, unknown, unknown> => Predicate.hasProperty(u, SubscribableTypeId)
|
||||||
extends Pipeable.Class implements Subscribable<A, E, R> {
|
|
||||||
readonly [TypeId]: TypeId = TypeId
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
readonly get: Effect.Effect<A, E, R>,
|
export const SubscribableImplTypeId: unique symbol = Symbol.for("@effect-fc/Lens/v4/SubscribableImpl")
|
||||||
readonly changes: Stream.Stream<A, E, R>,
|
export type SubscribableImplTypeId = typeof SubscribableImplTypeId
|
||||||
) {
|
|
||||||
super()
|
export declare namespace SubscribableImpl {
|
||||||
|
export interface Source<in out A, in out E = never, in out R = never> {
|
||||||
|
readonly get: Effect.Effect<A, E, R>
|
||||||
|
readonly changes: Stream.Stream<A, E, R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isSubscribable = (u: unknown): u is Subscribable<unknown, unknown, unknown> => Predicate.hasProperty(u, TypeId)
|
export class SubscribableImpl<in out A, in out E = never, in out R = never>
|
||||||
|
extends Pipeable.Class implements Subscribable<A, E, R> {
|
||||||
|
readonly [SubscribableTypeId]: SubscribableTypeId = SubscribableTypeId
|
||||||
|
readonly [SubscribableImplTypeId]: SubscribableImplTypeId = SubscribableImplTypeId
|
||||||
|
|
||||||
export const make = <A, E, R>(options: {
|
constructor(
|
||||||
readonly get: Effect.Effect<A, E, R>
|
readonly source: SubscribableImpl.Source<A, E, R>,
|
||||||
readonly changes: Stream.Stream<A, E, R>
|
) {
|
||||||
}): Subscribable<A, E, R> => new SubscribableImpl(options.get, options.changes)
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
export const fromSubscriptionRef = <A>(self: SubscriptionRef.SubscriptionRef<A>): Subscribable<A> => make({
|
get get() { return this.source.get }
|
||||||
get: SubscriptionRef.get(self),
|
get changes() { return this.source.changes }
|
||||||
changes: SubscriptionRef.changes(self),
|
}
|
||||||
|
|
||||||
|
export const isSubscribableImpl = (u: unknown): u is SubscribableImpl<unknown, unknown, unknown> => Predicate.hasProperty(u, SubscribableImplTypeId)
|
||||||
|
|
||||||
|
export const asSubscribableImpl = <A, E, R>(
|
||||||
|
subscribable: Subscribable<A, E, R>
|
||||||
|
): SubscribableImpl<A, E, R> => {
|
||||||
|
if (!isSubscribableImpl(subscribable))
|
||||||
|
throw new Error("Not a 'SubscribableImpl'")
|
||||||
|
return subscribable as SubscribableImpl<A, E, R>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const make = <A, E, R>(
|
||||||
|
source: SubscribableImpl.Source<A, E, R>
|
||||||
|
): Subscribable<A, E, R> => new SubscribableImpl(source)
|
||||||
|
|
||||||
|
export const unwrap = <A, E, R, E1, R1>(
|
||||||
|
effect: Effect.Effect<Subscribable<A, E, R>, E1, R1>,
|
||||||
|
): Subscribable<A, E | E1, R | R1> => make({
|
||||||
|
get: Effect.flatMap(effect, self => self.get),
|
||||||
|
changes: Stream.unwrap(Effect.map(effect, self => self.changes)),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export const map: {
|
export const map: {
|
||||||
<A, B>(f: (a: NoInfer<A>) => B): <E, R>(self: Subscribable<A, E, R>) => Subscribable<B, E, R>
|
<A, B>(f: (a: NoInfer<A>) => B): <E, R>(self: Subscribable<A, E, R>) => Subscribable<B, E, R>
|
||||||
<A, E, R, B>(self: Subscribable<A, E, R>, f: (a: NoInfer<A>) => B): Subscribable<B, E, R>
|
<A, E, R, B>(self: Subscribable<A, E, R>, f: (a: NoInfer<A>) => B): Subscribable<B, E, R>
|
||||||
@@ -65,13 +90,6 @@ export const mapEffect: {
|
|||||||
changes: Stream.mapEffect(self.changes, f),
|
changes: Stream.mapEffect(self.changes, f),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const unwrap = <A, E, R, E1, R1>(
|
|
||||||
effect: Effect.Effect<Subscribable<A, E, R>, E1, R1>,
|
|
||||||
): Subscribable<A, E | E1, R | R1> => make({
|
|
||||||
get: Effect.flatMap(effect, self => self.get),
|
|
||||||
changes: Stream.unwrap(Effect.map(effect, self => self.changes)),
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Maps over an `Option` value in the `Subscribable`. */
|
/** Maps over an `Option` value in the `Subscribable`. */
|
||||||
export const mapOption: {
|
export const mapOption: {
|
||||||
<A, B>(f: (a: A) => B): <E, R>(self: Subscribable<Option.Option<A>, E, R>) => Subscribable<Option.Option<B>, E, R>
|
<A, B>(f: (a: A) => B): <E, R>(self: Subscribable<Option.Option<A>, E, R>) => Subscribable<Option.Option<B>, E, R>
|
||||||
|
|||||||
Reference in New Issue
Block a user