6 people like it.
Like the snippet!
Simple CQRS Inventory
a simple CQRS example, inspired by the blogpost http://tojans.me/blog/2014/02/26/cqrs-and-functional-programming/
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
|
type Id = string
type Name = string
type Amount = int
type Command =
| CreateInventoryItem of Id
| RenameInventoryItem of Id * Name
| RemoveItemsFromInventory of Id * Amount
| AddItemsToInventory of Id * Amount
| DeactivateInventoryItem of Id
type Event =
| InventoryItemCreated of Id
| InventoryItemRenamed of Id * Name
| ItemsRemovedFromInventory of Id * Amount
| ItemsCheckedInToInventory of Id * Amount
| InventoryItemDeactivated of Id
type Item = { itemId : Id; activated : bool }
// NOTE: use Chessie or F# 4.1 instead
type Result<'TSuccess,'TFailure> =
| Ok of 'TSuccess
| Error of 'TFailure
let handle command someItem =
match someItem, command with
| None, CreateInventoryItem ID -> Ok [ InventoryItemCreated ID ]
| None, _ -> Error "please create the item first"
| Some item, CreateInventoryItem ID -> Error "item already created"
| Some item, DeactivateInventoryItem ID ->
if item.activated then Ok [InventoryItemDeactivated ID] else Error "already deactivated"
| Some item, _ when not item.activated -> Error "item is deactivated"
| Some item, RenameInventoryItem (ID, name) ->
if System.String.IsNullOrEmpty name then Error "invalid name"
else Ok [InventoryItemRenamed (ID, name) ]
| Some item, RemoveItemsFromInventory(ID, amount) ->
if amount <= 0 then Error "Can't remove negative amoutn from inventory"
else Ok [ItemsRemovedFromInventory (ID, amount)]
| Some item, AddItemsToInventory(ID, amount) ->
if amount <= 0 then Error "must have an amount > 0 to checkin to inventory"
else Ok [ItemsCheckedInToInventory(ID,amount)]
let applyEvent someItem event =
match someItem, event with
| None, InventoryItemCreated ID -> Some { itemId = ID; activated = true}
| Some item, InventoryItemDeactivated ID -> Some {item with activated = false }
| Some item, _ -> Some item
| None, _ -> None
let applyEvents = List.fold applyEvent
|
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
type Name = string
Full name: Script.Name
type Amount = int
Full name: Script.Amount
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type Command =
| CreateInventoryItem of Id
| RenameInventoryItem of Id * Name
| RemoveItemsFromInventory of Id * Amount
| AddItemsToInventory of Id * Amount
| DeactivateInventoryItem of Id
Full name: Script.Command
union case Command.CreateInventoryItem: Id -> Command
type Id = string
Full name: Script.Id
union case Command.RenameInventoryItem: Id * Name -> Command
union case Command.RemoveItemsFromInventory: Id * Amount -> Command
union case Command.AddItemsToInventory: Id * Amount -> Command
union case Command.DeactivateInventoryItem: Id -> Command
Multiple items
module Event
from Microsoft.FSharp.Control
--------------------
type Event =
| InventoryItemCreated of Id
| InventoryItemRenamed of Id * Name
| ItemsRemovedFromInventory of Id * Amount
| ItemsCheckedInToInventory of Id * Amount
| InventoryItemDeactivated of Id
Full name: Script.Event
--------------------
type Event<'T> =
new : unit -> Event<'T>
member Trigger : arg:'T -> unit
member Publish : IEvent<'T>
Full name: Microsoft.FSharp.Control.Event<_>
--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
new : unit -> Event<'Delegate,'Args>
member Trigger : sender:obj * args:'Args -> unit
member Publish : IEvent<'Delegate,'Args>
Full name: Microsoft.FSharp.Control.Event<_,_>
--------------------
new : unit -> Event<'T>
--------------------
new : unit -> Event<'Delegate,'Args>
union case Event.InventoryItemCreated: Id -> Event
union case Event.InventoryItemRenamed: Id * Name -> Event
union case Event.ItemsRemovedFromInventory: Id * Amount -> Event
union case Event.ItemsCheckedInToInventory: Id * Amount -> Event
union case Event.InventoryItemDeactivated: Id -> Event
type Item =
{itemId: Id;
activated: bool;}
Full name: Script.Item
Item.itemId: Id
Item.activated: bool
type bool = System.Boolean
Full name: Microsoft.FSharp.Core.bool
type Result<'TSuccess,'TFailure> =
| Ok of 'TSuccess
| Error of 'TFailure
Full name: Script.Result<_,_>
union case Result.Ok: 'TSuccess -> Result<'TSuccess,'TFailure>
union case Result.Error: 'TFailure -> Result<'TSuccess,'TFailure>
val handle : command:Command -> someItem:Item option -> Result<Event list,string>
Full name: Script.handle
val command : Command
val someItem : Item option
union case Option.None: Option<'T>
val ID : Id
union case Option.Some: Value: 'T -> Option<'T>
val item : Item
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
val name : Name
namespace System
Multiple items
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
Full name: System.String
--------------------
System.String(value: nativeptr<char>) : unit
System.String(value: nativeptr<sbyte>) : unit
System.String(value: char []) : unit
System.String(c: char, count: int) : unit
System.String(value: nativeptr<char>, startIndex: int, length: int) : unit
System.String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
System.String(value: char [], startIndex: int, length: int) : unit
System.String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: System.Text.Encoding) : unit
System.String.IsNullOrEmpty(value: string) : bool
val amount : Amount
val applyEvent : someItem:Item option -> event:Event -> Item option
Full name: Script.applyEvent
val event : Event
val applyEvents : (Item option -> Event list -> Item option)
Full name: Script.applyEvents
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
Full name: Microsoft.FSharp.Collections.List.fold
More information