From a184ecc6421f0ac01a7aea8229ce843746f7ddef Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 29 Nov 2024 13:33:41 +1300 Subject: [PATCH] reactivity hooks --- packages/experimental/src/EventLog.ts | 62 ++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/experimental/src/EventLog.ts b/packages/experimental/src/EventLog.ts index cc4c2050642..4d31245b249 100644 --- a/packages/experimental/src/EventLog.ts +++ b/packages/experimental/src/EventLog.ts @@ -21,6 +21,7 @@ import type { EventGroup } from "./EventGroup.js" import type { EventJournalError, RemoteEntry, RemoteId } from "./EventJournal.js" import { Entry, EventJournal, makeEntryId } from "./EventJournal.js" import { type EventLogRemote } from "./EventLogRemote.js" +import * as Reactivity from "./Reactivity.js" /** * @since 1.0.0 @@ -339,6 +340,29 @@ export const groupCompaction = ( }) }).pipe(Layer.scopedDiscard) +/** + * @since 1.0.0 + * @category reactivity + */ +export const groupReactivity = ( + group: EventGroup, + keys: + | { readonly [Tag in Event.Tag]?: ReadonlyArray } + | ReadonlyArray +): Layer.Layer => + Effect.gen(function*() { + const log = yield* EventLog + if (!Array.isArray(keys)) { + yield* log.registerReactivity(keys as any) + return + } + const obj: Record> = {} + for (const tag in group.events) { + obj[tag] = keys + } + yield* log.registerReactivity(obj) + }).pipe(Layer.scopedDiscard) + /** * @since 1.0.0 * @category layers @@ -398,6 +422,7 @@ export class EventLog extends Context.Tag("@effect/experimental/EventLog/EventLo readonly write: (entry: Entry) => Effect.Effect }) => Effect.Effect }) => Effect.Effect + readonly registerReactivity: (keys: Record>) => Effect.Effect readonly entries: Effect.Effect, EventJournalError> readonly destroy: Effect.Effect }>() {} @@ -417,6 +442,9 @@ const make = Effect.gen(function*() { }>() const journalSemaphore = yield* Effect.makeSemaphore(1) + const reactivity = yield* Reactivity.Reactivity + const reactivityKeys: Record> = {} + const runRemote = (remote: EventLogRemote) => Effect.gen(function*() { const startSequence = yield* journal.nextRemoteSequence(remote.id) @@ -502,6 +530,13 @@ const make = Effect.gen(function*() { entry, conflicts: decodedConflicts }) + if (reactivityKeys[entry.event]) { + for (const key of reactivityKeys[entry.event]) { + reactivity.unsafeInvalidate({ + [key]: [entry.primaryKey] + }) + } + } }).pipe( Effect.catchAllCause(Effect.log), Effect.annotateLogs({ @@ -558,11 +593,22 @@ const make = Effect.gen(function*() { primaryKey: handler.event.primaryKey(options.payload), payload, effect: (entry) => - handler.handler({ - payload: options.payload, - entry, - conflicts: [] - }) + Effect.tap( + handler.handler({ + payload: options.payload, + entry, + conflicts: [] + }), + () => { + if (reactivityKeys[entry.event]) { + for (const key of reactivityKeys[entry.event]) { + reactivity.unsafeInvalidate({ + [key]: [entry.primaryKey] + }) + } + } + } + ) })) }).pipe( Effect.mapInputContext((context) => Context.merge(handler.context, context)) @@ -595,6 +641,10 @@ const make = Effect.gen(function*() { } }) ), + registerReactivity: (keys) => + Effect.sync(() => { + Object.assign(reactivityKeys, keys) + }), destroy: journal.destroy }) }) @@ -604,7 +654,7 @@ const make = Effect.gen(function*() { * @category layers */ export const layerEventLog: Layer.Layer = Layer.scoped(EventLog, make).pipe( - Layer.provide(Registry.layer) + Layer.provide([Registry.layer, Reactivity.layer]) ) /**