Skip to content

Instantly share code, notes, and snippets.

@AlexSugak
Created April 8, 2014 12:53
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AlexSugak/10119582 to your computer and use it in GitHub Desktop.
Save AlexSugak/10119582 to your computer and use it in GitHub Desktop.
CQRS/Event Sourcing with F#, based on Greg Young's sample https://github.com/gregoryyoung/m-r and https://gist.github.com/ToJans/8219629#file-inventoryitems-hs
exception ItemAlreadyExists of string
exception ItemNotFound of string
exception DomainError of string
type Command =
| CreateInventoryItem of Id: int
| RenameInventoryItem of Id: int * Name: string
| RemoveItemsFromInventory of Id: int * Amount: int
| AddItemsToInventory of Id: int * Amount: int
| DeactivateInventoryItem of Id: int
type Event =
| InventoryItemCreated of Id: int
| InventoryItemRenamed of Id: int * Name: string
| ItemsRemovedFromInventory of Id: int * Amount: int
| ItemsCheckedInToInventory of Id: int * Amount: int
| InventoryItemDeactivated of Id: int
type InventoryItem = {
Id: int
Name: string option
Amount: int
IsDeactivated : bool
}
let apply item event =
match item, event with
| None, InventoryItemCreated(id) -> { Id = id; Name = None; IsDeactivated = false; Amount = 0; }
| None, _ -> raise (System.ArgumentException("unknown event"))
| Some(i), InventoryItemRenamed(id, name) -> { i with Name = Some(name); }
| Some(i), ItemsRemovedFromInventory(id, amount) -> { i with Amount = i.Amount - amount; }
| Some(i), ItemsCheckedInToInventory(id, amount) -> { i with Amount = i.Amount + amount; }
| Some(i), InventoryItemDeactivated(id) -> { i with IsDeactivated = true; }
| Some(i), _ -> i
let handle events command =
let item = events |> Seq.fold (fun acc e -> Some(apply acc e)) None
match item, command with
| None, CreateInventoryItem(id) -> [InventoryItemCreated(id)]
| Some(i), CreateInventoryItem(id) -> raise (ItemAlreadyExists("item already created"))
| None, _ -> raise (ItemNotFound("item not found"))
| Some(i), RenameInventoryItem(id, name) -> [InventoryItemRenamed(id, name)]
| Some(i), RemoveItemsFromInventory(id, amount) -> match i with
| i when i.Amount < amount -> raise (DomainError("item does not have enough inventory"))
| _ -> [ItemsRemovedFromInventory(id, amount)]
| Some(i), AddItemsToInventory(id, amount) -> [ItemsCheckedInToInventory(id, amount)]
| Some(i), DeactivateInventoryItem(id) -> match i with
| i when i.IsDeactivated -> raise (DomainError("item already deactivated"))
| _ -> [InventoryItemDeactivated(id)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment