Skip to content

Commit

Permalink
Update Tutorial fsx files to use #r nuget references (#309)
Browse files Browse the repository at this point in the history
This allows people to try out Equinox by just running the FSX alone. We might want to specify a version number in the #r references here but it works great.

* Tidy tutorial fsx files

Co-authored-by: Alan Ball <[email protected]>
  • Loading branch information
bartelink and voronoipotato authored Jan 18, 2022
1 parent 778cd5a commit 65552b2
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 86 deletions.
2 changes: 2 additions & 0 deletions Equinox.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Snapshotted/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
28 changes: 17 additions & 11 deletions samples/Tutorial/AsAt.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// - the same general point applies to over-using querying of streams for read purposes as we do here;
// applying CQRS principles can often lead to a better model regardless of raw necessity

#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#if VISUALSTUDIO
Expand All @@ -34,7 +35,12 @@
#r "Microsoft.Azure.Cosmos.Direct.dll"
#r "Microsoft.Azure.Cosmos.Client.dll"
#r "Equinox.CosmosStore.dll"

#else
#r "nuget:Serilog.Sinks.Console"
#r "nuget:Serilog.Sinks.Seq"
#r "nuget:Equinox.CosmosStore"
#r "nuget:Equinox.EventStore"
#endif
open System

let streamName clientId = FsCodec.StreamName.create "Account" clientId
Expand Down Expand Up @@ -133,8 +139,8 @@ module Log =
Equinox.CosmosStore.Core.Log.InternalMetrics.dump log
Equinox.EventStore.Log.InternalMetrics.dump log

let [<Literal>] appName = "equinox-tutorial"
let cache = Equinox.Cache(appName, 20)
let [<Literal>] AppName = "equinox-tutorial"
let cache = Equinox.Cache(AppName, 20)

module EventStore =

Expand All @@ -144,7 +150,7 @@ module EventStore =
// see QuickStart for how to run a local instance in a mode that emulates the behavior of a cluster
let host, username, password = "localhost", "admin", "changeit"
let connector = Connector(username,password,TimeSpan.FromSeconds 5., reqRetries=3, log=Logger.SerilogNormal Log.log)
let esc = connector.Connect(appName, Discovery.GossipDns host) |> Async.RunSynchronously
let esc = connector.Connect(AppName, Discovery.GossipDns host) |> Async.RunSynchronously
let log = Logger.SerilogNormal (Log.log)
let connection = EventStoreConnection(esc)
let context = EventStoreContext(connection, BatchingPolicy(maxBatchSize=snapshotWindow))
Expand All @@ -169,13 +175,13 @@ module Cosmos =
let category = CosmosStoreCategory(context, Events.codec, Fold.fold, Fold.initial, cacheStrategy, accessStrategy)
let resolve id = Equinox.Decider(Log.log, category.Resolve(streamName id), maxAttempts = 3)

let serviceES = Service(EventStore.resolve)
let serviceCosmos = Service(Cosmos.resolve)
//let serviceES = Service(EventStore.resolve)
let service= Service(Cosmos.resolve)

let client = "ClientA"
serviceES.Add(client, 1) |> Async.RunSynchronously
serviceES.Add(client, 3) |> Async.RunSynchronously
serviceES.Remove(client, 1) |> Async.RunSynchronously
serviceES.Read(client) |> Async.RunSynchronously |> printf "%A"
service.Add(client, 1) |> Async.RunSynchronously
service.Add(client, 3) |> Async.RunSynchronously
service.Remove(client, 1) |> Async.RunSynchronously
service.Read(client) |> Async.RunSynchronously |> printf "%A"

Log.dumpMetrics ()
Log.dumpMetrics ()
8 changes: 7 additions & 1 deletion samples/Tutorial/Cosmos.fsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#if VISUALSTUDIO
#r "netstandard"
Expand All @@ -18,6 +19,11 @@
#r "System.Net.Http"
#r "Serilog.Sinks.Seq.dll"
#r "Equinox.CosmosStore.dll"
#else
#r "nuget:Serilog.Sinks.Console"
#r "nuget:Serilog.Sinks.Seq"
#r "nuget:Equinox.CosmosStore"
#endif

module Log =

Expand Down
28 changes: 17 additions & 11 deletions samples/Tutorial/Counter.fsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Compile Tutorial.fsproj before attempting to send this to FSI with Alt-Enter by either:
// a) right-clicking or
// b) typing dotnet build samples/Tutorial
#if LOCAL
// Compile Tutorial.fsproj before attempting to send this to FSI with Alt-Enter by either:
// a) right-clicking or
// b) typing dotnet build samples/Tutorial
#I "bin/Debug/netstandard2.1/"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
Expand All @@ -10,15 +11,20 @@
#r "FSharp.UMX.dll"
#r "FsCodec.dll"
#r "FsCodec.NewtonsoftJson.dll"
#else
#r "nuget:Equinox.MemoryStore"
#r "nuget:FsCodec.Box"
#r "nuget:Serilog.Sinks.Console"
#endif

// Contributed by @voronoipotato

(* Events are things that have already happened,
(* Events are things that have already happened,
they always exist in the past, and should always be past tense verbs*)

(* A counter going up might clear to 0, but a counter going down might clear to 100. *)
type Cleared = { value : int }
type Event =
type Event =
| Incremented
| Decremented
| Cleared of Cleared
Expand All @@ -40,7 +46,7 @@ let evolve state event =
let fold state events = Seq.fold evolve state events

(* Commands are the things we intend to happen, though they may not*)
type Command =
type Command =
| Increment
| Decrement
| Clear of int
Expand All @@ -50,11 +56,11 @@ type Command =

let decide command (State state) =
match command with
| Increment ->
| Increment ->
if state > 100 then [] else [Incremented]
| Decrement ->
| Decrement ->
if state <= 0 then [] else [Decremented]
| Clear i ->
| Clear i ->
if state = i then [] else [Cleared {value = i}]

type Service internal (resolve : string -> Equinox.Decider<Event, State>) =
Expand Down Expand Up @@ -94,5 +100,5 @@ let clientId = "ClientA"
service.Read(clientId) |> Async.RunSynchronously
service.Execute(clientId, Increment) |> Async.RunSynchronously
service.Read(clientId) |> Async.RunSynchronously
service.Reset(clientId, 5) |> Async.RunSynchronously
service.Read(clientId) |> Async.RunSynchronously
service.Reset(clientId, 5) |> Async.RunSynchronously
service.Read(clientId) |> Async.RunSynchronously
40 changes: 23 additions & 17 deletions samples/Tutorial/Favorites.fsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#if LOCAL
// Compile Tutorial.fsproj by either a) right-clicking or b) typing
// dotnet build samples/Tutorial before attempting to send this to FSI with Alt-Enter
#I "bin/Debug/netstandard2.1/"
Expand All @@ -7,6 +8,10 @@
#r "Equinox.MemoryStore.dll"
#r "FSharp.UMX.dll"
#r "FSCodec.dll"
#else
#r "nuget:Equinox.MemoryStore"
#r "nuget:Serilog.Sinks.Console"
#endif

(*
* EVENTS
Expand All @@ -18,7 +23,7 @@
// i.e. typically records are used for the Event Payloads even in cases where you feel you'll only ever have a single primitive value

type Event =
| Added of string
| Added of string
| Removed of string
// No IUnionContract or Codec required as we're using a custom encoder in this example
// interface TypeShape.UnionContract.IUnionContract
Expand Down Expand Up @@ -59,7 +64,7 @@ let removeBEffect = interpret (Remove "b") favesCba
//val removeBEffect : Event list = [Removed "b"]

let favesCa = fold favesCba removeBEffect
// val favesCa : string list = ["c"; "a"]
// val favesCa : string list = ["c"; "a"]

let _removeBAgainEffect = interpret (Remove "b") favesCa
//val _removeBAgainEffect : Event list = []
Expand All @@ -74,9 +79,9 @@ let _removeBAgainEffect = interpret (Remove "b") favesCa

// Example of wrapping Decider to encapsulate stream access patterns (see DOCUMENTATION.md for reasons why this is not advised in real apps)
type Handler(decider : Equinox.Decider<Event, State>) =
member __.Execute command : Async<unit> =
member _.Execute command : Async<unit> =
decider.Transact(interpret command)
member __.Read : Async<string list> =
member _.Read : Async<string list> =
decider.Query id

(* When we Execute a command, Equinox.Decider will use `fold` and `interpret` to Decide whether Events need to be written
Expand Down Expand Up @@ -107,7 +112,7 @@ let codec =
| "Add", (:? string as x) -> Added x |> Some
| "Remove", (:? string as x) -> Removed x |> Some
| _ -> None
FsCodec.Codec.Create(encode,tryDecode)
FsCodec.Codec.Create(encode, tryDecode)
// Each store has a <Store>Category that is used to resolve IStream instances binding to a specific stream in a specific store
// ... because the nature of the contract with the handler is such that the store hands over State, we also pass the `initial` and `fold` as we used above
let cat = Equinox.MemoryStore.MemoryStoreCategory(store, codec, fold, initial)
Expand All @@ -120,10 +125,10 @@ let handler = Handler(clientAStream)

(* Run some commands *)

handler.Execute (Add "a") |> Async.RunSynchronously
handler.Execute (Add "b") |> Async.RunSynchronously
handler.Execute(Add "a") |> Async.RunSynchronously
handler.Execute(Add "b") |> Async.RunSynchronously
// Idempotency comes into play if we run it twice:
handler.Execute (Add "b") |> Async.RunSynchronously
handler.Execute(Add "b") |> Async.RunSynchronously

(* Read the current state *)

Expand All @@ -139,32 +144,33 @@ handler.Read |> Async.RunSynchronously

type Service(deciderFor : string -> Handler) =

member __.Favorite(clientId, sku) =
member _.Favorite(clientId, sku) =
let decider = deciderFor clientId
decider.Execute(Add sku)

member __.Unfavorite(clientId, skus) =
member _.Unfavorite(clientId, skus) =
let decider = deciderFor clientId
decider.Execute(Remove skus)

member __.List(clientId): Async<string list> =
member _.List(clientId): Async<string list> =
let decider = deciderFor clientId
decider.Read

(* See Counter.fsx and Cosmos.fsx for a more compact representation which makes the Handler wiring less obtrusive *)
let streamFor (clientId: string) =
let streamName = FsCodec.StreamName.create "Favorites" clientId
let decider = Equinox.Decider(log, cat.Resolve streamName, maxAttempts = 3)
let stream = cat.Resolve streamName
let decider = Equinox.Decider(log, stream, maxAttempts = 3)
Handler(decider)

let service = Service(streamFor)

let client = "ClientB"
service.Favorite(client, "a") |> Async.RunSynchronously
service.Favorite(client, "b") |> Async.RunSynchronously
service.List(client) |> Async.RunSynchronously
service.Favorite(client, "b") |> Async.RunSynchronously
service.List(client) |> Async.RunSynchronously
// val it : string list = ["b"; "a"]

service.Unfavorite(client, "b") |> Async.RunSynchronously
service.List(client) |> Async.RunSynchronously
//val it : string list = ["a"]
service.Unfavorite(client, "b") |> Async.RunSynchronously
service.List(client) |> Async.RunSynchronously
//val it : string list = ["a"]
39 changes: 22 additions & 17 deletions samples/Tutorial/FulfilmentCenter.fsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#if LOCAL
#I "bin/Debug/netstandard2.1/"
#r "Serilog.dll"
#r "Serilog.Sinks.Console.dll"
Expand All @@ -13,6 +14,13 @@
#r "System.Net.Http"
#r "Serilog.Sinks.Seq.dll"
#r "Equinox.CosmosStore.dll"
#else
#r "nuget:Equinox.MemoryStore"
#r "nuget:Equinox.CosmosStore"
#r "nuget:FsCodec.NewtonsoftJson"
#r "nuget:Serilog.Sinks.Console"
#r "nuget:Serilog.Sinks.Seq"
#endif

open FSharp.UMX

Expand All @@ -27,13 +35,13 @@ module Types =
type FcDetails = { dcCode : string; countryCode : string; financialGroupCode : string }

type FcName = { code : string; name : string }

type Address =
{ address1 : string
address2 : string
city : string
state : string
zip : string
zip : string
isBusiness : bool option
isWeekendDeliveries : bool option
businessName : string option }
Expand Down Expand Up @@ -97,12 +105,12 @@ module FulfilmentCenter =
let decider = resolve fc
decider.QueryEx(fun c -> c.Version, projection c.State)

member __.UpdateName(id, value) = execute id (Register value)
member __.UpdateAddress(id, value) = execute id (UpdateAddress value)
member __.UpdateContact(id, value) = execute id (UpdateContact value)
member __.UpdateDetails(id, value) = execute id (UpdateDetails value)
member __.Read id : Async<Summary> = read id
member __.QueryWithVersion(id, render : Fold.State -> 'res) : Async<int64*'res> = queryEx id render
member _.UpdateName(id, value) = execute id (Register value)
member _.UpdateAddress(id, value) = execute id (UpdateAddress value)
member _.UpdateContact(id, value) = execute id (UpdateContact value)
member _.UpdateDetails(id, value) = execute id (UpdateDetails value)
member _.Read id : Async<Summary> = read id
member _.QueryWithVersion(id, render : Fold.State -> 'res) : Async<int64*'res> = queryEx id render

open Equinox.CosmosStore
open System
Expand Down Expand Up @@ -139,7 +147,7 @@ let service = Service(resolve)

let fc = "fc0"
service.UpdateName(fc, { code="FC000"; name="Head" }) |> Async.RunSynchronously
service.Read(fc) |> Async.RunSynchronously
service.Read(fc) |> Async.RunSynchronously

Log.dumpMetrics ()

Expand Down Expand Up @@ -171,12 +179,9 @@ module FulfilmentCenterSummary =

type Service internal (resolve : string -> Equinox.Decider<Events.Event, State>) =

let execute fc command : Async<unit> =
let decider = resolve fc
decider.Transact(interpret command)
let read fc : Async<Summary option> =
let decider = resolve fc
member _.Update(id, version, value) =
let decider = resolve id
decider.Transact(interpret (Update (version,value)))
member _.TryRead id : Async<Summary option> =
let decider = resolve id
decider.Query(Option.map (fun s -> s.state))

member __.Update(id, version, value) = execute id (Update (version,value))
member __.TryRead id : Async<Summary option> = read id
10 changes: 5 additions & 5 deletions samples/Tutorial/Gapless.fs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ let decideRelease item (state : Fold.State) : Events.Event list =

type Service internal (resolve : SequenceId -> Equinox.Decider<Events.Event, Fold.State>) =

member __.ReserveMany(series,count) : Async<int64 list> =
member _.ReserveMany(series,count) : Async<int64 list> =
let decider = resolve series
decider.Transact(decideReserve count)

member __.Reserve(series) : Async<int64> = async {
let! res = __.ReserveMany(series,1)
member x.Reserve(series) : Async<int64> = async {
let! res = x.ReserveMany(series, 1)
return List.head res }

member __.Confirm(series,item) : Async<unit> =
member _.Confirm(series,item) : Async<unit> =
let decider = resolve series
decider.Transact(decideConfirm item)

member __.Release(series,item) : Async<unit> =
member _.Release(series,item) : Async<unit> =
let decider = resolve series
decider.Transact(decideRelease item)

Expand Down
4 changes: 2 additions & 2 deletions samples/Tutorial/Index.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ let interpret add remove (state : Fold.State<'v>) =

type Service<'t> internal (decider : Equinox.Decider<Events.Event<'t>, Fold.State<'t>>) =

member __.Ingest(adds : seq<string*'t>, removes : string seq) : Async<int*int> =
member _.Ingest(adds : seq<string*'t>, removes : string seq) : Async<int*int> =
decider.Transact(interpret adds removes)
member __.Read() : Async<Map<string,'t>> =
member _.Read() : Async<Map<string,'t>> =
decider.Query id

let create<'t> resolve indexId =
Expand Down
Loading

0 comments on commit 65552b2

Please sign in to comment.