From 8a46d85259b3e8da06d1f674f8fef774d8d1d3a1 Mon Sep 17 00:00:00 2001 From: Jesse Kelly Date: Tue, 7 May 2024 23:10:26 +0200 Subject: [PATCH 1/2] added Rx.sub(Subscribable) (#120) --- .changeset/witty-buckets-kiss.md | 5 ++ docs/rx/Rx.ts.md | 65 ++++++++++++++++++++-- packages/rx/src/Rx.ts | 93 ++++++++++++++++++++++++++------ packages/rx/test/Rx.test.ts | 28 ++++++++-- 4 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 .changeset/witty-buckets-kiss.md diff --git a/.changeset/witty-buckets-kiss.md b/.changeset/witty-buckets-kiss.md new file mode 100644 index 0000000..0ae5ac6 --- /dev/null +++ b/.changeset/witty-buckets-kiss.md @@ -0,0 +1,5 @@ +--- +"@effect-rx/rx": minor +--- + +added Rx.subscribable for working with Subscribables diff --git a/docs/rx/Rx.ts.md b/docs/rx/Rx.ts.md index fcdedc7..3ddf322 100644 --- a/docs/rx/Rx.ts.md +++ b/docs/rx/Rx.ts.md @@ -31,7 +31,8 @@ Added in v1.0.0 - [make](#make) - [pull](#pull) - [readable](#readable) - - [subRef](#subref) + - [subscribable](#subscribable) + - [subscriptionRef](#subscriptionref) - [writable](#writable) - [context](#context-1) - [Context (interface)](#context-interface) @@ -45,6 +46,9 @@ Added in v1.0.0 - [Get (type alias)](#get-type-alias) - [GetResult (type alias)](#getresult-type-alias) - [Infer (type alias)](#infer-type-alias) + - [InferFailure (type alias)](#inferfailure-type-alias) + - [InferPullSuccess (type alias)](#inferpullsuccess-type-alias) + - [InferSuccess (type alias)](#infersuccess-type-alias) - [Mount (type alias)](#mount-type-alias) - [Read (type alias)](#read-type-alias) - [ReadFn (type alias)](#readfn-type-alias) @@ -323,12 +327,29 @@ export declare const readable: (read: Rx.Read, refresh?: Rx.Refresh) => Rx Added in v1.0.0 -## subRef +## subscribable **Signature** ```ts -export declare const subRef: { +export declare const subscribable: { + (ref: Subscribable.Subscribable | Rx.Read>): Rx + ( + effect: + | Effect.Effect, E, never> + | Rx.Read, E, never>> + ): Rx +} +``` + +Added in v1.0.0 + +## subscriptionRef + +**Signature** + +```ts +export declare const subscriptionRef: { (ref: SubscriptionRef.SubscriptionRef | Rx.Read>): Writable ( effect: @@ -507,6 +528,36 @@ export type Infer> = T extends Rx ? A : never Added in v1.0.0 +### InferFailure (type alias) + +**Signature** + +```ts +export type InferFailure> = T extends Rx> ? E : never +``` + +Added in v1.0.0 + +### InferPullSuccess (type alias) + +**Signature** + +```ts +export type InferPullSuccess> = T extends Rx> ? A : never +``` + +Added in v1.0.0 + +### InferSuccess (type alias) + +**Signature** + +```ts +export type InferSuccess> = T extends Rx> ? A : never +``` + +Added in v1.0.0 + ### Mount (type alias) **Signature** @@ -681,11 +732,17 @@ export interface RxRuntime extends Rx, E } ) => Writable, void> - readonly subRef: ( + readonly subscriptionRef: ( create: | Effect.Effect, E, R> | Rx.Read, E, R>> ) => Writable, A> + + readonly subscribable: ( + create: + | Effect.Effect, E1, R> + | Rx.Read, E1, R>> + ) => Rx> } ``` diff --git a/packages/rx/src/Rx.ts b/packages/rx/src/Rx.ts index edf57b9..a8e9991 100644 --- a/packages/rx/src/Rx.ts +++ b/packages/rx/src/Rx.ts @@ -18,6 +18,7 @@ import { type Pipeable, pipeArguments } from "effect/Pipeable" import * as Runtime from "effect/Runtime" import * as Scope from "effect/Scope" import * as Stream from "effect/Stream" +import * as Subscribable from "effect/Subscribable" import * as SubscriptionRef from "effect/SubscriptionRef" import * as internalRegistry from "./internal/registry.js" import { runCallbackSync } from "./internal/runtime.js" @@ -299,7 +300,7 @@ const RxRuntimeProto = { return makeStreamPull(pullRx as any, options) }, - subRef(this: RxRuntime, arg: any) { + subscriptionRef(this: RxRuntime, arg: any) { return makeSubRef(readable((get) => { const previous = get.self>() const runtimeResult = get(this) @@ -313,6 +314,22 @@ const RxRuntimeProto = { runtimeResult.value ) })) + }, + + subscribable(this: RxRuntime, arg: any) { + return makeSubscribable(readable((get) => { + const previous = get.self>() + const runtimeResult = get(this) + if (runtimeResult._tag !== "Success") { + return Result.replacePrevious(runtimeResult, previous) + } + return makeEffect( + get, + arg, + Result.initial(true), + runtimeResult.value + ) + })) } } @@ -547,11 +564,17 @@ export interface RxRuntime extends Rx, E readonly initialValue?: ReadonlyArray }) => Writable, void> - readonly subRef: ( + readonly subscriptionRef: ( create: | Effect.Effect, E, R> | Rx.Read, E, R>> ) => Writable, A> + + readonly subscribable: ( + create: + | Effect.Effect, E1, R> + | Rx.Read, E1, R>> + ) => Rx> } /** @@ -655,25 +678,28 @@ function makeStream( // constructors - subscription ref // ----------------------------------------------------------------------------- -const makeSubRef = ( - refRx: Rx | Result.Result, any>> -) => { - function read(get: Context) { - const ref = get(refRx) - if (SubscriptionRef.SubscriptionRefTypeId in ref) { +/** @internal */ +const readSubscribable = + (subRx: Rx | Result.Result, any>>) => + (get: Context) => { + const sub = get(subRx) + if (Subscribable.TypeId in sub) { get.addFinalizer( - ref.changes.pipe( + sub.changes.pipe( Stream.runForEach((value) => get.setSelf(value)), Effect.runCallback ) ) - return Effect.runSync(SubscriptionRef.get(ref)) - } else if (ref._tag !== "Success") { - return ref + return Effect.runSync(sub.get) + } else if (sub._tag !== "Success") { + return sub } - return makeStream(get, ref.value.changes, Result.initial(true)) + return makeStream(get, sub.value.changes, Result.initial(true)) } +const makeSubRef = ( + refRx: Rx | Result.Result, any>> +) => { function write(ctx: WriteContext>, value: any) { const ref = ctx.get(refRx) if (SubscriptionRef.SubscriptionRefTypeId in ref) { @@ -683,14 +709,14 @@ const makeSubRef = ( } } - return writable(read, write) + return writable(readSubscribable(refRx), write) } /** * @since 1.0.0 * @category constructors */ -export const subRef: { +export const subscriptionRef: { (ref: SubscriptionRef.SubscriptionRef | Rx.Read>): Writable ( effect: @@ -715,6 +741,43 @@ export const subRef: { return Effect.isEffect(value) ? makeEffect(get, value, Result.initial(true)) : value })) +// ----------------------------------------------------------------------------- +// constructors - subscribable +// ----------------------------------------------------------------------------- + +const makeSubscribable = ( + subRx: Rx | Result.Result, any>> +) => readable(readSubscribable(subRx)) + +/** + * @since 1.0.0 + * @category constructors + */ +export const subscribable: { + (ref: Subscribable.Subscribable | Rx.Read>): Rx + ( + effect: + | Effect.Effect, E, never> + | Rx.Read, E, never>> + ): Rx +} = ( + ref: + | Subscribable.Subscribable + | Rx.Read> + | Effect.Effect, any, never> + | Rx.Read, any, never>> +) => + makeSubscribable(readable((get) => { + let value: Subscribable.Subscribable | Effect.Effect, any, any> + if (typeof ref === "function") { + value = ref(get) + } else { + value = ref + } + + return Effect.isEffect(value) ? makeEffect(get, value, Result.initial(true)) : value + })) + // ----------------------------------------------------------------------------- // constructors - functions // ----------------------------------------------------------------------------- diff --git a/packages/rx/test/Rx.test.ts b/packages/rx/test/Rx.test.ts index aba62f3..a9d3ca5 100644 --- a/packages/rx/test/Rx.test.ts +++ b/packages/rx/test/Rx.test.ts @@ -1,7 +1,7 @@ import * as Registry from "@effect-rx/rx/Registry" import * as Result from "@effect-rx/rx/Result" import * as Rx from "@effect-rx/rx/Rx" -import { Cause, Either, FiberRef, SubscriptionRef } from "effect" +import { Cause, Either, FiberRef, Subscribable, SubscriptionRef } from "effect" import * as Context from "effect/Context" import * as Effect from "effect/Effect" import * as Hash from "effect/Hash" @@ -775,10 +775,30 @@ describe("Rx", () => { assert.deepStrictEqual(r.get(rx), Either.right(123)) }) + it("Subscribable", async () => { + vitest.useRealTimers() + const sub = Subscribable.make({ get: Effect.succeed(123), changes: Stream.empty }) + const rx = Rx.subscribable(sub) + const r = Registry.make() + const unmount = r.mount(rx) + assert.deepStrictEqual(r.get(rx), 123) + unmount() + }) + + it("Subscribable/SubscriptionRef", async () => { + vitest.useRealTimers() + const ref = SubscriptionRef.make(123).pipe(Effect.runSync) + const rx = Rx.subscribable(ref) + const r = Registry.make() + assert.deepStrictEqual(r.get(rx), 123) + await Effect.runPromise(SubscriptionRef.update(ref, (a) => a + 1)) + assert.deepStrictEqual(r.get(rx), 124) + }) + it("SubscriptionRef", async () => { vitest.useRealTimers() const ref = SubscriptionRef.make(0).pipe(Effect.runSync) - const rx = Rx.subRef(ref) + const rx = Rx.subscriptionRef(ref) const r = Registry.make() const unmount = r.mount(rx) assert.deepStrictEqual(r.get(rx), 0) @@ -789,7 +809,7 @@ describe("Rx", () => { }) it("SubscriptionRef/effect", async () => { - const rx = Rx.subRef(SubscriptionRef.make(0)) + const rx = Rx.subscriptionRef(SubscriptionRef.make(0)) const r = Registry.make() const unmount = r.mount(rx) assert.deepStrictEqual(r.get(rx), Result.success(0, true)) @@ -800,7 +820,7 @@ describe("Rx", () => { }) it("SubscriptionRef/runtime", async () => { - const rx = counterRuntime.subRef(SubscriptionRef.make(0)) + const rx = counterRuntime.subscriptionRef(SubscriptionRef.make(0)) const r = Registry.make() const unmount = r.mount(rx) assert.deepStrictEqual(r.get(rx), Result.success(0, true)) From 592c6d289ed2bf615d96b127ba8a9eae4506dcb1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 09:11:51 +1200 Subject: [PATCH 2/2] Version Packages (#125) Co-authored-by: github-actions[bot] --- .changeset/witty-buckets-kiss.md | 5 ----- packages/rx-react/CHANGELOG.md | 7 +++++++ packages/rx-react/package.json | 2 +- packages/rx-vue/CHANGELOG.md | 7 +++++++ packages/rx-vue/package.json | 2 +- packages/rx/CHANGELOG.md | 6 ++++++ packages/rx/package.json | 2 +- 7 files changed, 23 insertions(+), 8 deletions(-) delete mode 100644 .changeset/witty-buckets-kiss.md diff --git a/.changeset/witty-buckets-kiss.md b/.changeset/witty-buckets-kiss.md deleted file mode 100644 index 0ae5ac6..0000000 --- a/.changeset/witty-buckets-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@effect-rx/rx": minor ---- - -added Rx.subscribable for working with Subscribables diff --git a/packages/rx-react/CHANGELOG.md b/packages/rx-react/CHANGELOG.md index 4a5ba48..ea4df82 100644 --- a/packages/rx-react/CHANGELOG.md +++ b/packages/rx-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @effect-rx/rx-react +## 0.28.5 + +### Patch Changes + +- Updated dependencies [[`8a46d85`](https://github.com/tim-smart/effect-rx/commit/8a46d85259b3e8da06d1f674f8fef774d8d1d3a1)]: + - @effect-rx/rx@0.30.0 + ## 0.28.4 ### Patch Changes diff --git a/packages/rx-react/package.json b/packages/rx-react/package.json index 9271bbb..8ecafbc 100644 --- a/packages/rx-react/package.json +++ b/packages/rx-react/package.json @@ -1,6 +1,6 @@ { "name": "@effect-rx/rx-react", - "version": "0.28.4", + "version": "0.28.5", "description": "Reactive toolkit for Effect", "type": "module", "publishConfig": { diff --git a/packages/rx-vue/CHANGELOG.md b/packages/rx-vue/CHANGELOG.md index 062ef11..671169f 100644 --- a/packages/rx-vue/CHANGELOG.md +++ b/packages/rx-vue/CHANGELOG.md @@ -1,5 +1,12 @@ # @effect-rx/rx-vue +## 0.8.5 + +### Patch Changes + +- Updated dependencies [[`8a46d85`](https://github.com/tim-smart/effect-rx/commit/8a46d85259b3e8da06d1f674f8fef774d8d1d3a1)]: + - @effect-rx/rx@0.30.0 + ## 0.8.4 ### Patch Changes diff --git a/packages/rx-vue/package.json b/packages/rx-vue/package.json index d3e285d..6aff12d 100644 --- a/packages/rx-vue/package.json +++ b/packages/rx-vue/package.json @@ -1,6 +1,6 @@ { "name": "@effect-rx/rx-vue", - "version": "0.8.4", + "version": "0.8.5", "description": "Reactive toolkit for Effect", "type": "module", "publishConfig": { diff --git a/packages/rx/CHANGELOG.md b/packages/rx/CHANGELOG.md index 772585a..e5ea520 100644 --- a/packages/rx/CHANGELOG.md +++ b/packages/rx/CHANGELOG.md @@ -1,5 +1,11 @@ # @effect-rx/rx +## 0.30.0 + +### Minor Changes + +- [#120](https://github.com/tim-smart/effect-rx/pull/120) [`8a46d85`](https://github.com/tim-smart/effect-rx/commit/8a46d85259b3e8da06d1f674f8fef774d8d1d3a1) Thanks [@jessekelly881](https://github.com/jessekelly881)! - added Rx.subscribable for working with Subscribables + ## 0.29.4 ### Patch Changes diff --git a/packages/rx/package.json b/packages/rx/package.json index 1a02506..81e7831 100644 --- a/packages/rx/package.json +++ b/packages/rx/package.json @@ -1,6 +1,6 @@ { "name": "@effect-rx/rx", - "version": "0.29.4", + "version": "0.30.0", "description": "Reactive toolkit for Effect", "type": "module", "publishConfig": {