Skip to content

Commit

Permalink
Add Light example
Browse files Browse the repository at this point in the history
  • Loading branch information
bartelink committed Dec 15, 2023
1 parent 12df223 commit fed3cbf
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 31 deletions.
1 change: 1 addition & 0 deletions samples/Store/Domain.Tests/Domain.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<Compile Include="ContactPreferencesTests.fs" />
<Compile Include="FavoritesTests.fs" />
<Compile Include="SavedForLaterTests.fs" />
<Compile Include="LightTests.fs" />
</ItemGroup>

<ItemGroup>
Expand Down
27 changes: 27 additions & 0 deletions samples/Store/Domain.Tests/LightTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Domain.Tests.LightTests

open Domain.Light
open Swensen.Unquote

type Cases = Off | On | After3Cycles
let establish = function
| Off -> initial
| On -> fold initial [| SwitchedOn |]
| After3Cycles -> [| for _ in 1..3 do SwitchedOn; SwitchedOff |] |> fold initial

let run cmd state =
let events = decideSwitch cmd state
events, fold state events

let [<FsCheck.Xunit.Property>] props case cmd =
let state = establish case
let events, state = run cmd state
match case, cmd with
| Off, true -> events =! [| SwitchedOn |]
| Off, false -> events =! [||]
| On, true -> events =! [||]
| On, false -> events =! [| SwitchedOff |]
| After3Cycles, true -> events =! [| Broke |]
| After3Cycles, false -> events =! [||]

[||] = decideSwitch cmd state // all commands are idempotent
53 changes: 22 additions & 31 deletions samples/Store/Domain/Light.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,33 @@ module Domain.Light

// By Jérémie Chassaing / @thinkb4coding
// https://github.com/dddeu/dddeu20-talks-jeremie-chassaing-functional-event-sourcing/blob/main/EventSourcing.fsx#L52-L84
type Command =

| SwitchOn
| SwitchOff
type Event =
| SwitchedOn
| SwitchedOff
| Broke

type Status =
| On
| Off

type Working =
{ Status : Status
RemainingUses: int}

type State =
| Working of Working
| Working of CurrentState
| Broken
let initialState = Working { Status = Off; RemainingUses = 3}

let decide (command: Command) (state: State) : Event list =
match state, command with
| Working { Status = Off; RemainingUses = 0 }, SwitchOn ->
[ Broke]
| Working { Status = Off}, SwitchOn -> [ SwitchedOn]
| Working { Status = On }, SwitchOff -> [SwitchedOff]
| _ -> []
and CurrentState = { on: bool; remainingUses: int }
let initial = Working { on = false; remainingUses = 3 }
let evolve s e =
match s with
| Broken -> s
| Working s ->
match e with
| SwitchedOn -> Working { on = true; remainingUses = s.remainingUses - 1 }
| SwitchedOff -> Working { s with on = false }
| Broke -> Broken
let fold = Array.fold evolve

let evolve (state: State) (event: Event) : State =
match state, event with
| _, Broke -> Broken
| Working s, SwitchedOn ->
Working { Status = On;
RemainingUses = s.RemainingUses - 1 }
| Working s, SwitchedOff ->
Working { s with Status = Off}
| _ -> state
let decideSwitch (on: bool) s = [|
match s with
| Broken -> ()
| Working { on = true } ->
if not on then
SwitchedOff
| Working { on = false; remainingUses = r } ->
if on then
if r = 0 then Broke
else SwitchedOn |]

0 comments on commit fed3cbf

Please sign in to comment.