<commit_before>-- | This program shows very basic usage of an event store. We create a very
-- simple Counter Projection/Aggregate that holds an integer between 0 and 100.
-- The CLI asks the user for commands and applies them to an in-memory event
-- store.

module Main where

import Control.Concurrent.STM
import Control.Monad (forever, void)
import Safe (readMay)

import Eventful
import Eventful.Store.Memory

main :: IO ()
main = do
  -- Create the event store and run loop forever
  store <- memoryEventStore
  forever (readAndApplyCommand store)

readAndApplyCommand :: MemoryEventStore -> IO ()
readAndApplyCommand store = do
  -- Just use the nil uuid for everything
  let uuid = nil

  -- Get current state and print it out
  (currentState, _) <- atomically . runEventStore store $ getLatestProjection counterProjection nil
  putStrLn $ "Current state: " ++ show currentState

  -- Ask user for command
  putStrLn "Enter a command. (IncrementCounter n, DecrementCounter n, ResetCounter):"
  input <- getLine

  -- Parse command and apply
  case readMay input of
    Nothing -> putStrLn "Unknown command"
    (Just command) ->
      case aggregateCommand counterAggregate currentState command of
        -- The command is valid. Apply the event to the store.
        Right event -> do
          putStrLn $ "Command valid. Event: " ++ show event
          void . atomically . runEventStore store $ storeEvent AnyVersion uuid event
        -- The command is invalid. Show the user the error.
        Left err -> putStrLn $ "Command invalid: Error: " ++ show err

  -- Run loop again
  putStrLn ""
  readAndApplyCommand store

-- | This is the state for our Counter projection.
newtype CounterState = CounterState { unCounterState :: Int }
  deriving (Eq, Show)

-- | This specifies the possible events we can use for our counter. In our
-- case, we only have one event to add an amount to a counter. Notice the use
-- of past-tense. Events record things that happened in the past.
data CounterEvent
  = CounterAmountAdded Int
  deriving (Eq, Show)

-- | This ties together the state and event types into a 'Projection'.
type CounterProjection = Projection CounterState CounterEvent

counterProjection :: CounterProjection
counterProjection =
  Projection
  (CounterState 0)
  (\(CounterState k) (CounterAmountAdded x) -> CounterState (k + x))<commit_msg>Fix counter CLI example storing event lists<commit_after>-- | This program shows very basic usage of an event store. We create a very
-- simple Counter Projection/Aggregate that holds an integer between 0 and 100.
-- The CLI asks the user for commands and applies them to an in-memory event
-- store.

module Main where

import Control.Concurrent.STM
import Control.Monad (forever, void)
import Safe (readMay)

import Eventful
import Eventful.Store.Memory

main :: IO ()
main = do
  -- Create the event store and run loop forever
  store <- memoryEventStore
  forever (readAndApplyCommand store)

readAndApplyCommand :: MemoryEventStore -> IO ()
readAndApplyCommand store = do
  -- Just use the nil uuid for everything
  let uuid = nil

  -- Get current state and print it out
  (currentState, _) <- atomically . runEventStore store $ getLatestProjection counterProjection uuid
  putStrLn $ "Current state: " ++ show currentState

  -- Ask user for command
  putStrLn "Enter a command. (IncrementCounter n, DecrementCounter n, ResetCounter):"
  input <- getLine

  -- Parse command and apply
  case readMay input of
    Nothing -> putStrLn "Unknown command"
    (Just command) ->
      case aggregateCommand counterAggregate currentState command of
        -- The command is valid. Apply the event to the store.
        Right events -> do
          putStrLn $ "Command valid. Event: " ++ show events
          void . atomically . runEventStore store $ storeEvents AnyVersion uuid events
        -- The command is invalid. Show the user the error.
        Left err -> putStrLn $ "Command invalid: Error: " ++ show err

  -- Run loop again
  putStrLn ""
  readAndApplyCommand store

-- | This is the state for our Counter projection.
newtype CounterState = CounterState { unCounterState :: Int }
  deriving (Eq, Show)

-- | This specifies the possible events we can use for our counter. In our
-- case, we only have one event to add an amount to a counter. Notice the use
-- of past-tense. Events record things that happened in the past.
data CounterEvent
  = CounterAmountAdded Int
  deriving (Eq, Show)

-- | This ties together the state and event types into a 'Projection'.
type CounterProjection = Projection CounterState CounterEvent

counterProjection :: CounterProjection
counterProjection =
  Projection
  (CounterState 0)
  (\(CounterState k) (CounterAmountAdded x) -> CounterState (k + x))
{'fraction_non_alphanumeric': 0.07186383694053372, 'fraction_numerical': 0.002101281781886951, 'mean_word_length': 3.395198522622345, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3611061', 'n_tokens_mistral': 1303, 'n_tokens_neox': 1261, 'n_words': 575}