From 65552b2f33740a0fb036238d3ab1d403a88ae662 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Tue, 18 Jan 2022 22:41:48 +0000 Subject: [PATCH] Update Tutorial fsx files to use #r nuget references (#309) 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 --- Equinox.sln.DotSettings | 2 ++ samples/Tutorial/AsAt.fsx | 28 +++++++++++-------- samples/Tutorial/Cosmos.fsx | 8 +++++- samples/Tutorial/Counter.fsx | 28 +++++++++++-------- samples/Tutorial/Favorites.fsx | 40 +++++++++++++++------------ samples/Tutorial/FulfilmentCenter.fsx | 39 ++++++++++++++------------ samples/Tutorial/Gapless.fs | 10 +++---- samples/Tutorial/Index.fs | 4 +-- samples/Tutorial/Sequence.fs | 13 +-------- samples/Tutorial/Set.fs | 4 +-- samples/Tutorial/Todo.fsx | 9 ++++-- samples/Tutorial/Tutorial.fsproj | 5 +--- samples/Tutorial/Upload.fs | 4 +-- 13 files changed, 108 insertions(+), 86 deletions(-) create mode 100644 Equinox.sln.DotSettings diff --git a/Equinox.sln.DotSettings b/Equinox.sln.DotSettings new file mode 100644 index 000000000..ab51fff63 --- /dev/null +++ b/Equinox.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/samples/Tutorial/AsAt.fsx b/samples/Tutorial/AsAt.fsx index 4ea04dc9b..39474c7ef 100644 --- a/samples/Tutorial/AsAt.fsx +++ b/samples/Tutorial/AsAt.fsx @@ -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 @@ -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 @@ -133,8 +139,8 @@ module Log = Equinox.CosmosStore.Core.Log.InternalMetrics.dump log Equinox.EventStore.Log.InternalMetrics.dump log -let [] appName = "equinox-tutorial" -let cache = Equinox.Cache(appName, 20) +let [] AppName = "equinox-tutorial" +let cache = Equinox.Cache(AppName, 20) module EventStore = @@ -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)) @@ -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 () \ No newline at end of file +Log.dumpMetrics () diff --git a/samples/Tutorial/Cosmos.fsx b/samples/Tutorial/Cosmos.fsx index b05f67240..f54dc7ec9 100644 --- a/samples/Tutorial/Cosmos.fsx +++ b/samples/Tutorial/Cosmos.fsx @@ -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" @@ -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 = diff --git a/samples/Tutorial/Counter.fsx b/samples/Tutorial/Counter.fsx index c587cc1d1..26feaf321 100644 --- a/samples/Tutorial/Counter.fsx +++ b/samples/Tutorial/Counter.fsx @@ -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" @@ -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 @@ -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 @@ -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) = @@ -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 \ No newline at end of file +service.Reset(clientId, 5) |> Async.RunSynchronously +service.Read(clientId) |> Async.RunSynchronously diff --git a/samples/Tutorial/Favorites.fsx b/samples/Tutorial/Favorites.fsx index a312159b8..893f73c4f 100644 --- a/samples/Tutorial/Favorites.fsx +++ b/samples/Tutorial/Favorites.fsx @@ -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/" @@ -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 @@ -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 @@ -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 = [] @@ -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) = - member __.Execute command : Async = + member _.Execute command : Async = decider.Transact(interpret command) - member __.Read : Async = + member _.Read : Async = decider.Query id (* When we Execute a command, Equinox.Decider will use `fold` and `interpret` to Decide whether Events need to be written @@ -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 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) @@ -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 *) @@ -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 = + member _.List(clientId): Async = 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"] \ No newline at end of file +service.Unfavorite(client, "b") |> Async.RunSynchronously +service.List(client) |> Async.RunSynchronously +//val it : string list = ["a"] diff --git a/samples/Tutorial/FulfilmentCenter.fsx b/samples/Tutorial/FulfilmentCenter.fsx index 086acdbc0..c33a2f024 100644 --- a/samples/Tutorial/FulfilmentCenter.fsx +++ b/samples/Tutorial/FulfilmentCenter.fsx @@ -1,3 +1,4 @@ +#if LOCAL #I "bin/Debug/netstandard2.1/" #r "Serilog.dll" #r "Serilog.Sinks.Console.dll" @@ -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 @@ -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 } @@ -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 = read id - member __.QueryWithVersion(id, render : Fold.State -> 'res) : Async = 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 = read id + member _.QueryWithVersion(id, render : Fold.State -> 'res) : Async = queryEx id render open Equinox.CosmosStore open System @@ -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 () @@ -171,12 +179,9 @@ module FulfilmentCenterSummary = type Service internal (resolve : string -> Equinox.Decider) = - let execute fc command : Async = - let decider = resolve fc - decider.Transact(interpret command) - let read fc : Async = - let decider = resolve fc + member _.Update(id, version, value) = + let decider = resolve id + decider.Transact(interpret (Update (version,value))) + member _.TryRead id : Async = + 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 = read id diff --git a/samples/Tutorial/Gapless.fs b/samples/Tutorial/Gapless.fs index df3be8e91..ac1e540f6 100644 --- a/samples/Tutorial/Gapless.fs +++ b/samples/Tutorial/Gapless.fs @@ -56,19 +56,19 @@ let decideRelease item (state : Fold.State) : Events.Event list = type Service internal (resolve : SequenceId -> Equinox.Decider) = - member __.ReserveMany(series,count) : Async = + member _.ReserveMany(series,count) : Async = let decider = resolve series decider.Transact(decideReserve count) - member __.Reserve(series) : Async = async { - let! res = __.ReserveMany(series,1) + member x.Reserve(series) : Async = async { + let! res = x.ReserveMany(series, 1) return List.head res } - member __.Confirm(series,item) : Async = + member _.Confirm(series,item) : Async = let decider = resolve series decider.Transact(decideConfirm item) - member __.Release(series,item) : Async = + member _.Release(series,item) : Async = let decider = resolve series decider.Transact(decideRelease item) diff --git a/samples/Tutorial/Index.fs b/samples/Tutorial/Index.fs index e65399d61..91840f477 100644 --- a/samples/Tutorial/Index.fs +++ b/samples/Tutorial/Index.fs @@ -40,9 +40,9 @@ let interpret add remove (state : Fold.State<'v>) = type Service<'t> internal (decider : Equinox.Decider, Fold.State<'t>>) = - member __.Ingest(adds : seq, removes : string seq) : Async = + member _.Ingest(adds : seq, removes : string seq) : Async = decider.Transact(interpret adds removes) - member __.Read() : Async> = + member _.Read() : Async> = decider.Query id let create<'t> resolve indexId = diff --git a/samples/Tutorial/Sequence.fs b/samples/Tutorial/Sequence.fs index 9ed27dcdb..387c6ae3c 100644 --- a/samples/Tutorial/Sequence.fs +++ b/samples/Tutorial/Sequence.fs @@ -7,17 +7,6 @@ open System let [] Category = "Sequence" let streamName id = FsCodec.StreamName.create Category (SequenceId.toString id) -// shim for net461 -module Seq = - let tryLast (source : seq<_>) = - use e = source.GetEnumerator() - if e.MoveNext() then - let mutable res = e.Current - while (e.MoveNext()) do res <- e.Current - Some res - else - None - // NOTE - these types and the union case names reflect the actual storage formats and hence need to be versioned with care module Events = @@ -43,7 +32,7 @@ let decideReserve (count : int) (state : Fold.State) : int64 * Events.Event list type Service internal (resolve : SequenceId -> Equinox.Decider) = /// Reserves an id, yielding the reserved value. Optional count enables reserving more than the default count of 1 in a single transaction - member __.Reserve(series,?count) : Async = + member _.Reserve(series,?count) : Async = let decider = resolve series decider.Transact(decideReserve (defaultArg count 1)) diff --git a/samples/Tutorial/Set.fs b/samples/Tutorial/Set.fs index 848072a9f..30039753b 100644 --- a/samples/Tutorial/Set.fs +++ b/samples/Tutorial/Set.fs @@ -40,10 +40,10 @@ let interpret add remove (state : Fold.State) = type Service internal (decider : Equinox.Decider) = - member __.Add(add : string seq, remove : string seq) : Async = + member _.Add(add : string seq, remove : string seq) : Async = decider.Transact(interpret add remove) - member __.Read() : Async> = + member _.Read() : Async> = decider.Query id let create resolveStream setId = diff --git a/samples/Tutorial/Todo.fsx b/samples/Tutorial/Todo.fsx index 0ec081cbb..93b3b9822 100644 --- a/samples/Tutorial/Todo.fsx +++ b/samples/Tutorial/Todo.fsx @@ -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" @@ -16,7 +17,11 @@ #r "FSharp.Control.AsyncSeq.dll" #r "Microsoft.Azure.Cosmos.Client.dll" #r "Equinox.CosmosStore.dll" - +#else +#r "nuget:Equinox.CosmosStore" +#r "nuget:Serilog.Sinks.Console" +#r "nuget:Serilog.Sinks.Seq" +#endif open System (* NB It's recommended to look at Favorites.fsx first as it establishes the groundwork diff --git a/samples/Tutorial/Tutorial.fsproj b/samples/Tutorial/Tutorial.fsproj index 4f9c1926c..aff7dcdfe 100644 --- a/samples/Tutorial/Tutorial.fsproj +++ b/samples/Tutorial/Tutorial.fsproj @@ -4,7 +4,6 @@ netstandard2.1 5 true - true @@ -30,10 +29,8 @@ - - - \ No newline at end of file + diff --git a/samples/Tutorial/Upload.fs b/samples/Tutorial/Upload.fs index bf48ad2ef..daf2e853c 100644 --- a/samples/Tutorial/Upload.fs +++ b/samples/Tutorial/Upload.fs @@ -1,4 +1,4 @@ -/// Simple example of how one might have multiple uploaders agree/share a common UploadId for a given OrderId +/// Simple example of how one might have multiple instances of an uploader app agree/share a common UploadId for a given OrderId module Upload open FSharp.UMX @@ -58,7 +58,7 @@ let decide (value : UploadId) (state : Fold.State) : Choice * type Service internal (resolve : CompanyId * PurchaseOrderId -> Equinox.Decider) = - member __.Sync(companyId, purchaseOrderId, value) : Async> = + member _.Sync(companyId, purchaseOrderId, value) : Async> = let decider = resolve (companyId, purchaseOrderId) decider.Transact(decide value)