Header menu logo FCQRS

Wiring Commands

We wire the command handler to the actor. The command handler is a function that takes a command and a state and returns an event. The event is then persisted to the event store.

First the register command:

let register cid userName password =

    // Create an actor id from the username. Using ValueLens technique to create an ActorId. See my video.
    let actorId: ActorId = userName |> ValueLens.CreateAsResult |> Result.value

    let command = User.Register(userName, password)

    // Condition to wait until what we are interested in happens.
    let condition (e: User.Event) =
        e.IsAlreadyRegistered || e.IsRegisterSucceeded

    // Send the command to the actor.
    let subscribe = userSubs cid actorId command condition

    async {
        // Wait for the event to happen andd decide the outcome.
        match! subscribe with
        | { EventDetails = User.RegisterSucceeded _
            Version = v } -> return Ok v

        | { EventDetails = User.AlreadyRegistered
            Version = _ } -> 
            return Error [ sprintf "User %s is already registered" 
                <| actorId.ToString() ]
        | _ -> 
            return Error [ sprintf "Unexpected event for registration %s" 
                    <| actorId.ToString() ]
    }

Next the login command:

let login cid userName password =

    let actorId: ActorId = userName |> ValueLens.CreateAsResult |> Result.value

    let command = User.Login password

    let condition (e: User.Event) = e.IsLoginFailed || e.IsLoginSucceeded

    let subscribe = userSubs cid actorId command condition

    async {
        match! subscribe with
        | { EventDetails = User.LoginSucceeded
            Version = v } -> return Ok v

        | { EventDetails = User.LoginFailed
            Version = _ } -> 
                return Error [ sprintf "User %s Login failed" 
                    <| actorId.ToString() ]
        | _ -> 
            return Error [ sprintf "Unexpected event for user %s" 
                <| actorId.ToString() ]
    }
namespace FCQRS
namespace FCQRS.Model
module Data from FCQRS.Model
module Bootstrap
val register: cid: CID -> userName: string -> password: string -> Async<Result<'a,string list>>
val cid: CID
val userName: string
val password: string
val actorId: ActorId
type ActorId = private | ActorId of ShortString member Equals: ActorId * IEqualityComparer -> bool override ToString: unit -> string member IsValid: bool static member Value_: (ActorId -> ShortString) * (ShortString -> ActorId -> ActorId)
type ValueLens = static member Create: innerValue: 'Inner -> 'Wrapped (requires member Value_) static member CreateAsResult: v: 'a -> Result<'b,'d> (requires member Value_ and member Value_) static member IsValidValue: this: 'Wrapped -> bool (requires member Value_) static member Isvalid: this: 'a -> bool (requires member Value_ and member Value_) static member ToString: this: 'Wrapped -> string (requires member Value_) static member TryCreate: innerValue: 'Inner -> Result<'Wrapped,'Error> (requires member Value_) static member Value: this: 'Wrapped -> 'Inner (requires member Value_) + 1 overload
static member ValueLens.CreateAsResult: v: 'a -> Result<'b,'d> (requires member Value_ and member Value_)
Multiple items
module Result from FCQRS.Model.Data

--------------------
module Result from Microsoft.FSharp.Core

--------------------
[<Struct>] type Result<'T,'TError> = | Ok of ResultValue: 'T | Error of ErrorValue: 'TError
val value: e: Result<'a,'b> -> 'a
val command: User.Command
module User
union case User.Command.Register: string * string -> User.Command
val condition: e: User.Event -> bool
val e: User.Event
type Event = | LoginSucceeded | LoginFailed | RegisterSucceeded of string * string | AlreadyRegistered member Equals: Event * IEqualityComparer -> bool member IsAlreadyRegistered: bool member IsLoginFailed: bool member IsLoginSucceeded: bool member IsRegisterSucceeded: bool
property User.Event.IsAlreadyRegistered: bool with get
property User.Event.IsRegisterSucceeded: bool with get
val subscribe: (Map<string,string> option -> Async<FCQRS.Common.Event<User.Event>>)
val userSubs: cid: CID -> actorId: ActorId -> command: 'a -> filter: ('b -> bool) -> metadata: Map<string,string> option -> Async<FCQRS.Common.Event<'b>>
val async: AsyncBuilder
union case User.Event.RegisterSucceeded: string * string -> User.Event
type Version = private | Version of int64 member Equals: Version * IEqualityComparer -> bool override ToString: unit -> string static member Value_: (Version -> int64) * (int64 -> Version -> Result<Version,ModelError>) static member Zero: Version
<summary> Aggregate Version </summary>
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
union case User.Event.AlreadyRegistered: User.Event
union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>
val sprintf: format: Printf.StringFormat<'T> -> 'T
override ActorId.ToString: unit -> string
val login: cid: CID -> userName: string -> password: string -> Async<Result<'a,string list>>
union case User.Command.Login: string -> User.Command
property User.Event.IsLoginFailed: bool with get
property User.Event.IsLoginSucceeded: bool with get
union case User.Event.LoginSucceeded: User.Event
union case User.Event.LoginFailed: User.Event

Type something to start searching.