Skip to content

Instantly share code, notes, and snippets.

@ToJans
Last active January 19, 2024 10:47
Show Gist options
  • Save ToJans/8219629 to your computer and use it in GitHub Desktop.
Save ToJans/8219629 to your computer and use it in GitHub Desktop.
Haskell implementation of Greg Young's CQRS sample: https://github.com/gregoryyoung/m-r Love the sheer elegance of Haskell; no need for all that infrastructure crap
module InventoryItems(Command(..), Event(..), handle) where
import Data.Maybe(isJust)
type Id = String
type Name = String
type Amount = Int
data Command = CreateInventoryItem Id
| RenameInventoryItem Id Name
| RemoveItemsFromInventory Id Amount
| AddItemsToInventory Id Amount
| DeactivateInventoryItem Id
deriving (Show)
data Event = InventoryItemCreated Id
| InventoryItemRenamed Id Name
| ItemsRemovedFromInventory Id Amount
| ItemsCheckedInToInventory Id Amount
| InventoryItemDeactivated Id
deriving (Show, Read)
data Item = Item { itemId :: Id
, itemActivated :: Bool
}
handle :: [Event] -> Command -> [Event]
handle events command =
handle' item command
where item = apply events
handle' maybeItem (CreateInventoryItem id)
| itemExists = error "item already created"
| otherwise = [InventoryItemCreated id]
where itemExists = isJust maybeItem
handle' Nothing _command = error "please create the item first"
handle' (Just item) (DeactivateInventoryItem id)
| deactivated = error "already deactivated"
| otherwise = [InventoryItemDeactivated id]
where deactivated = not (itemActivated item)
handle' (Just Item {itemActivated = False}) _command = error "item is deactivated"
handle' (Just item) (RenameInventoryItem id name)
| invalidName = error "newName"
| otherwise = [InventoryItemRenamed id name]
where invalidName = name == []
handle' (Just item) (RemoveItemsFromInventory id amount)
| invalidAmount = error "can't remove negative amount from inventory"
| otherwise = [ItemsRemovedFromInventory id amount]
where invalidAmount = amount <= 0
handle' (Just item) (AddItemsToInventory id amount)
| invalidAmount = error "must have an amount > 0 to checkin to inventory"
| otherwise = [ItemsCheckedInToInventory id amount]
where invalidAmount = amount <= 0
apply events = foldl apply' Nothing events
apply' Nothing (InventoryItemCreated id) = Just (Item id True)
apply' (Just item) (InventoryItemDeactivated id) = Just (item {itemActivated = False})
apply' (Just item) _ = Just item
@yevhen
Copy link

yevhen commented Jan 2, 2014

There is no neeed for any of that infrastructure crap in C# either, even including DelegateAdjuster. I believe that Greg was just having fun (trolling actually). All that crap, including DelegateAdjuster could be substituted by using dynamic and casting to object.

@yevhen
Copy link

yevhen commented Jan 2, 2014

Stii, on overall, it won't be that terse in C#, fo sure :)

@ToJans
Copy link
Author

ToJans commented Jan 3, 2014

Agreed!

@henry-hz
Copy link

This is more than elegance, it's an electronic poem :) Just a fantastic comparison.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment