Hindsight – Type-safe and evolvable event sourcing for Haskell

1 hour ago 2

Type-Safe Event Definition

Define events with compile-time versioning guarantees. No runtime surprises.

-- Event definition instance Event "user_registered" -- Event payload data UserInfo = UserInfo { userId :: Text , email :: Text } deriving (Generic, FromJSON, ToJSON) -- Version declaration type instance MaxVersion UserRegistered = 0 type instance Versions UserRegistered = '[UserInfo] -- Migration (automatic for single version) instance MigrateVersion 0 UserRegistered

Backend-Agnostic Subscriptions

Subscribe to events with handlers that work across all backends.

{-# LANGUAGE RequiredTypeArguments #-} -- Subscribe to events (works with any backend) subscribeToUsers :: BackendHandle backend -> IO (SubscriptionHandle backend) subscribeToUsers store = subscribe store ( match "user_registered" handleUser :? MatchEnd ) (EventSelector AllStreams FromBeginning) where -- Handler runs for each event handleUser envelope = do let user = envelope.payload putStrLn $ "New user: " <> user.email return Continue

SQL Projection Handlers

Transform events into queryable read models with ACID guarantees.

{-# LANGUAGE RequiredTypeArguments #-} -- Projection handler (PostgreSQL transactions) userProjection :: ProjectionHandler "user_registered" backend userProjection envelope = do let user = envelope.payload -- Execute SQL in transaction statement () $ Statement sql encoder decoder True where sql = "INSERT INTO users (id, email) VALUES ($1, $2)" encoder = contrazip2 (param (nonNullable text)) (param (nonNullable text))

Flexible Backend Choice

Start simple, scale when ready. Same API, different backends.

-- File system store fsStore :: IO (BackendHandle FilesystemStore) sqlStore = newFilesystemStore "./events" -- PostgreSQL store sqlStore :: IO (BackendHandle PostgreSQLStore) sqlStore = do pool <- createPool postgresSettings newPostgreSQLStore pool -- Same operations, different backends insertEvents devStore Nothing batch insertEvents sqlStore Nothing batch
Read Entire Article