├── .gitignore
├── .paket
└── paket.bootstrapper.exe
├── LICENSE
├── README.md
├── build.cmd
├── build.fsx
├── build.sh
├── ex1
├── README.md
├── done
│ ├── LibAAS.App
│ │ ├── App.config
│ │ ├── App.fs
│ │ ├── App.fsx
│ │ ├── AssemblyInfo.fs
│ │ ├── LibAAS.App.fsproj
│ │ └── Program.fs
│ ├── LibAAS.Contracts
│ │ ├── AssemblyInfo.fs
│ │ ├── Commands.fs
│ │ ├── Events.fs
│ │ ├── LibAAS.Contracts.fsproj
│ │ ├── Script.fsx
│ │ └── Types.fs
│ ├── LibAAS.Domain
│ │ ├── App.config
│ │ ├── AssemblyInfo.fs
│ │ ├── CommandHandling.fs
│ │ ├── DomainEntry.fs
│ │ ├── DomainTypes.fs
│ │ ├── Inventory.fs
│ │ ├── LibAAS.Domain.fsproj
│ │ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ │ ├── AgentHelper.fs
│ │ ├── AssemblyInfo.fs
│ │ ├── ErrorHandling.fs
│ │ ├── EventStore.fs
│ │ ├── LibAAS.Infrastructure.fsproj
│ │ └── Script.fsx
│ ├── LibAAS.Tests
│ │ ├── AssemblyInfo.fs
│ │ ├── InventoryTests.fs
│ │ ├── LibAAS.Tests.fsproj
│ │ ├── LoanTests.fs
│ │ ├── Specification.fs
│ │ ├── TestHelpers.fs
│ │ ├── app.config
│ │ └── packages.config
│ └── LibAAS.sln
└── start
│ ├── LibAAS.App
│ ├── App.config
│ ├── App.fs
│ ├── App.fsx
│ ├── AssemblyInfo.fs
│ ├── LibAAS.App.fsproj
│ └── Program.fs
│ ├── LibAAS.Contracts
│ ├── AssemblyInfo.fs
│ ├── Commands.fs
│ ├── Events.fs
│ ├── LibAAS.Contracts.fsproj
│ ├── Script.fsx
│ └── Types.fs
│ ├── LibAAS.Domain
│ ├── App.config
│ ├── AssemblyInfo.fs
│ ├── CommandHandling.fs
│ ├── DomainEntry.fs
│ ├── DomainTypes.fs
│ ├── Inventory.fs
│ ├── LibAAS.Domain.fsproj
│ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ ├── AgentHelper.fs
│ ├── AssemblyInfo.fs
│ ├── ErrorHandling.fs
│ ├── EventStore.fs
│ ├── LibAAS.Infrastructure.fsproj
│ └── Script.fsx
│ ├── LibAAS.Tests
│ ├── AssemblyInfo.fs
│ ├── InventoryTests.fs
│ ├── LibAAS.Tests.fsproj
│ ├── LoanTests.fs
│ ├── Specification.fs
│ ├── TestHelpers.fs
│ ├── app.config
│ └── packages.config
│ └── LibAAS.sln
├── ex2
├── README.md
├── done
│ ├── LibAAS.App
│ │ ├── App.config
│ │ ├── App.fs
│ │ ├── App.fsx
│ │ ├── AssemblyInfo.fs
│ │ ├── LibAAS.App.fsproj
│ │ └── Program.fs
│ ├── LibAAS.Contracts
│ │ ├── AssemblyInfo.fs
│ │ ├── Commands.fs
│ │ ├── Events.fs
│ │ ├── LibAAS.Contracts.fsproj
│ │ ├── Script.fsx
│ │ └── Types.fs
│ ├── LibAAS.Domain
│ │ ├── App.config
│ │ ├── AssemblyInfo.fs
│ │ ├── CommandHandling.fs
│ │ ├── DomainEntry.fs
│ │ ├── DomainTypes.fs
│ │ ├── Inventory.fs
│ │ ├── LibAAS.Domain.fsproj
│ │ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ │ ├── AgentHelper.fs
│ │ ├── AssemblyInfo.fs
│ │ ├── ErrorHandling.fs
│ │ ├── EventStore.fs
│ │ ├── LibAAS.Infrastructure.fsproj
│ │ └── Script.fsx
│ ├── LibAAS.Tests
│ │ ├── AssemblyInfo.fs
│ │ ├── InventoryTests.fs
│ │ ├── LibAAS.Tests.fsproj
│ │ ├── LoanTests.fs
│ │ ├── Specification.fs
│ │ ├── TestHelpers.fs
│ │ ├── app.config
│ │ └── packages.config
│ └── LibAAS.sln
└── start
│ ├── LibAAS.App
│ ├── App.config
│ ├── App.fs
│ ├── App.fsx
│ ├── AssemblyInfo.fs
│ ├── LibAAS.App.fsproj
│ └── Program.fs
│ ├── LibAAS.Contracts
│ ├── AssemblyInfo.fs
│ ├── Commands.fs
│ ├── Events.fs
│ ├── LibAAS.Contracts.fsproj
│ ├── Script.fsx
│ └── Types.fs
│ ├── LibAAS.Domain
│ ├── App.config
│ ├── AssemblyInfo.fs
│ ├── CommandHandling.fs
│ ├── DomainEntry.fs
│ ├── DomainTypes.fs
│ ├── Inventory.fs
│ ├── LibAAS.Domain.fsproj
│ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ ├── AgentHelper.fs
│ ├── AssemblyInfo.fs
│ ├── ErrorHandling.fs
│ ├── EventStore.fs
│ ├── LibAAS.Infrastructure.fsproj
│ └── Script.fsx
│ ├── LibAAS.Tests
│ ├── AssemblyInfo.fs
│ ├── InventoryTests.fs
│ ├── LibAAS.Tests.fsproj
│ ├── LoanTests.fs
│ ├── Specification.fs
│ ├── TestHelpers.fs
│ ├── app.config
│ └── packages.config
│ └── LibAAS.sln
├── ex3
├── README.md
├── done
│ ├── LibAAS.App
│ │ ├── App.config
│ │ ├── App.fs
│ │ ├── App.fsx
│ │ ├── AssemblyInfo.fs
│ │ ├── LibAAS.App.fsproj
│ │ └── Program.fs
│ ├── LibAAS.Contracts
│ │ ├── AssemblyInfo.fs
│ │ ├── Commands.fs
│ │ ├── Events.fs
│ │ ├── LibAAS.Contracts.fsproj
│ │ ├── Script.fsx
│ │ └── Types.fs
│ ├── LibAAS.Domain
│ │ ├── App.config
│ │ ├── AssemblyInfo.fs
│ │ ├── CommandHandling.fs
│ │ ├── DomainEntry.fs
│ │ ├── DomainTypes.fs
│ │ ├── Inventory.fs
│ │ ├── LibAAS.Domain.fsproj
│ │ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ │ ├── AgentHelper.fs
│ │ ├── AssemblyInfo.fs
│ │ ├── ErrorHandling.fs
│ │ ├── EventStore.fs
│ │ ├── LibAAS.Infrastructure.fsproj
│ │ └── Script.fsx
│ ├── LibAAS.Tests
│ │ ├── AssemblyInfo.fs
│ │ ├── InventoryTests.fs
│ │ ├── LibAAS.Tests.fsproj
│ │ ├── LoanTests.fs
│ │ ├── Specification.fs
│ │ ├── TestHelpers.fs
│ │ ├── app.config
│ │ └── packages.config
│ └── LibAAS.sln
└── start
│ ├── LibAAS.App
│ ├── App.config
│ ├── App.fs
│ ├── App.fsx
│ ├── AssemblyInfo.fs
│ ├── LibAAS.App.fsproj
│ └── Program.fs
│ ├── LibAAS.Contracts
│ ├── AssemblyInfo.fs
│ ├── Commands.fs
│ ├── Events.fs
│ ├── LibAAS.Contracts.fsproj
│ ├── Script.fsx
│ └── Types.fs
│ ├── LibAAS.Domain
│ ├── App.config
│ ├── AssemblyInfo.fs
│ ├── CommandHandling.fs
│ ├── DomainEntry.fs
│ ├── DomainTypes.fs
│ ├── Inventory.fs
│ ├── LibAAS.Domain.fsproj
│ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ ├── AgentHelper.fs
│ ├── AssemblyInfo.fs
│ ├── ErrorHandling.fs
│ ├── EventStore.fs
│ ├── LibAAS.Infrastructure.fsproj
│ └── Script.fsx
│ ├── LibAAS.Tests
│ ├── AssemblyInfo.fs
│ ├── InventoryTests.fs
│ ├── LibAAS.Tests.fsproj
│ ├── LoanTests.fs
│ ├── Specification.fs
│ ├── TestHelpers.fs
│ ├── app.config
│ └── packages.config
│ └── LibAAS.sln
├── ex4
├── README.md
├── done
│ ├── LibAAS.App
│ │ ├── App.config
│ │ ├── App.fs
│ │ ├── App.fsx
│ │ ├── AssemblyInfo.fs
│ │ ├── LibAAS.App.fsproj
│ │ └── Program.fs
│ ├── LibAAS.Contracts
│ │ ├── AssemblyInfo.fs
│ │ ├── Commands.fs
│ │ ├── Events.fs
│ │ ├── LibAAS.Contracts.fsproj
│ │ ├── Script.fsx
│ │ └── Types.fs
│ ├── LibAAS.Domain
│ │ ├── App.config
│ │ ├── AssemblyInfo.fs
│ │ ├── CommandHandling.fs
│ │ ├── DomainEntry.fs
│ │ ├── DomainTypes.fs
│ │ ├── Inventory.fs
│ │ ├── LibAAS.Domain.fsproj
│ │ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ │ ├── AgentHelper.fs
│ │ ├── AssemblyInfo.fs
│ │ ├── ErrorHandling.fs
│ │ ├── EventStore.fs
│ │ ├── LibAAS.Infrastructure.fsproj
│ │ └── Script.fsx
│ ├── LibAAS.Tests
│ │ ├── AssemblyInfo.fs
│ │ ├── InventoryTests.fs
│ │ ├── LibAAS.Tests.fsproj
│ │ ├── LoanTests.fs
│ │ ├── Specification.fs
│ │ ├── TestHelpers.fs
│ │ ├── app.config
│ │ └── packages.config
│ └── LibAAS.sln
└── start
│ ├── LibAAS.App
│ ├── App.config
│ ├── App.fs
│ ├── App.fsx
│ ├── AssemblyInfo.fs
│ ├── LibAAS.App.fsproj
│ └── Program.fs
│ ├── LibAAS.Contracts
│ ├── AssemblyInfo.fs
│ ├── Commands.fs
│ ├── Events.fs
│ ├── LibAAS.Contracts.fsproj
│ ├── Script.fsx
│ └── Types.fs
│ ├── LibAAS.Domain
│ ├── App.config
│ ├── AssemblyInfo.fs
│ ├── CommandHandling.fs
│ ├── DomainEntry.fs
│ ├── DomainTypes.fs
│ ├── Inventory.fs
│ ├── LibAAS.Domain.fsproj
│ └── Loan.fs
│ ├── LibAAS.Infrastructure
│ ├── AgentHelper.fs
│ ├── AssemblyInfo.fs
│ ├── ErrorHandling.fs
│ ├── EventStore.fs
│ ├── LibAAS.Infrastructure.fsproj
│ └── Script.fsx
│ ├── LibAAS.Tests
│ ├── AssemblyInfo.fs
│ ├── InventoryTests.fs
│ ├── LibAAS.Tests.fsproj
│ ├── LoanTests.fs
│ ├── Specification.fs
│ ├── TestHelpers.fs
│ ├── app.config
│ └── packages.config
│ └── LibAAS.sln
├── paket.dependencies
└── paket.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 | node_modules/
5 | dist/
6 |
7 | # mstest test results
8 | TestResults
9 |
10 | ## Ignore Visual Studio temporary files, build results, and
11 | ## files generated by popular Visual Studio add-ons.
12 |
13 | # User-specific files
14 | *.suo
15 | *.user
16 | *.sln.docstates
17 |
18 | # Build results
19 | [Dd]ebug/
20 | [Rr]elease/
21 | x64/
22 | *_i.c
23 | *_p.c
24 | *.ilk
25 | *.meta
26 | *.obj
27 | *.pch
28 | *.pdb
29 | *.pgc
30 | *.pgd
31 | *.rsp
32 | *.sbr
33 | *.tlb
34 | *.tli
35 | *.tlh
36 | *.tmp
37 | *.log
38 | *.vspscc
39 | *.vssscc
40 | .builds
41 | .build
42 | .test
43 | .deploy
44 |
45 | # Visual C++ cache files
46 | ipch/
47 | *.aps
48 | *.ncb
49 | *.opensdf
50 | *.sdf
51 |
52 | # Visual Studio profiler
53 | *.psess
54 | *.vsp
55 | *.vspx
56 |
57 | # Guidance Automation Toolkit
58 | *.gpState
59 |
60 | # ReSharper is a .NET coding add-in
61 | _ReSharper*
62 |
63 | # NCrunch
64 | *.ncrunch*
65 | .*crunch*.local.xml
66 |
67 | # Installshield output folder
68 | [Ee]xpress
69 |
70 | # DocProject is a documentation generator add-in
71 | DocProject/buildhelp/
72 | DocProject/Help/*.HxT
73 | DocProject/Help/*.HxC
74 | DocProject/Help/*.hhc
75 | DocProject/Help/*.hhk
76 | DocProject/Help/*.hhp
77 | DocProject/Help/Html2
78 | DocProject/Help/html
79 |
80 | # Click-Once directory
81 | publish
82 |
83 | # Publish Web Output
84 | *.Publish.xml
85 |
86 | # NuGet Packages Directory
87 | packages
88 |
89 | # Windows Azure Build Output
90 | csx
91 | *.build.csdef
92 |
93 | # Windows Store app package directory
94 | AppPackages/
95 |
96 | # Others
97 | [Bb]in
98 | [Oo]bj
99 | sql
100 | TestResults
101 | [Tt]est[Rr]esult*
102 | *.Cache
103 | ClientBin
104 | [Ss]tyle[Cc]op.*
105 | ~$*
106 | *.dbmdl
107 | Generated_Code #added for RIA/Silverlight projects
108 |
109 | # Backup & report files from converting an old project file to a newer
110 | # Visual Studio version. Backup files are not needed, because we have git ;-)
111 | _UpgradeReport_Files/
112 | Backup*/
113 | UpgradeLog*.XML
114 |
115 | src/Rapporteringsregisteret.Web/assets/less/*.css
116 |
117 | MetricResults/
118 | *.sln.ide/
119 |
120 | _configs/
121 | .fake/
122 | .paket/
--------------------------------------------------------------------------------
/.paket/paket.bootstrapper.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mastoj/LibAAS/f70da85093375b2d1bfd078cb26896795cc39eef/.paket/paket.bootstrapper.exe
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Tomas Jansson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | ".paket/paket.bootstrapper.exe"
2 | ".paket/paket.exe" "restore"
3 |
4 | "./packages/FAKE/tools/FAKE.exe" %* "--fsiargs" "build.fsx"
5 |
--------------------------------------------------------------------------------
/build.fsx:
--------------------------------------------------------------------------------
1 | #r @"packages/FAKE/tools/FakeLib.dll"
2 | open System
3 | open Fake
4 | open Fake.Testing.XUnit2
5 |
6 | let testDir = ".test"
7 |
8 | let targetName = getBuildParam "target"
9 | trace (sprintf "Target name: %s" targetName)
10 | let targets = ["Ex1Start";"Ex1Done";"Ex2Start";"Ex2Done";"Ex3Start";"Ex3Done";"Ex4Start";"Ex4Start"] |> List.map (fun s -> s.ToLower())
11 |
12 | if targets |> List.contains (targetName.ToLower()) |> not then
13 | let targetNames = String.Join("|", targets)
14 | let msg = sprintf "Missing target, use: ./build.sh <%s>" targetNames
15 | targets |> String.concat "|" |> sprintf "Missing target, use: ./build.sh <%s>" |> traceError
16 | exit -1
17 | let (proj,version) = (targetName.Substring(0,3), targetName.Substring(3))
18 | let basePath = sprintf "./%s/%s" proj version
19 |
20 | // Add targets so they are found by the Ionide FAKE plugin
21 | Target "Ex1Start" ignore
22 | Target "Ex1Done" ignore
23 | Target "Ex2Start" ignore
24 | Target "Ex2Done" ignore
25 | Target "Ex3Start" ignore
26 | Target "Ex3Done" ignore
27 | Target "Ex4Start" ignore
28 | Target "Ex4Done" ignore
29 |
30 | Target "Default" (fun _ ->
31 | trace "Hello default"
32 | )
33 |
34 | Target "RestorePackages" (fun _ ->
35 | let packagesFolder = basePath > "packages"
36 | !!(basePath > "**/packages.config")
37 | |> Seq.iter
38 | (RestorePackage (fun parameters ->
39 | { parameters with
40 | OutputPath = packagesFolder}))
41 | )
42 |
43 | Target "Build" (fun _ ->
44 | trace (sprintf "Building %s %s" proj version)
45 | let sln = !! (basePath > "*.sln")
46 | trace (sprintf "Will build solution: %A" sln)
47 | sln
48 | |> MSBuildDebug "" "Rebuild"
49 | |> ignore
50 | )
51 |
52 | Target "Test" (fun _ ->
53 | let testDlls = !!(basePath > "*.Tests/bin/Debug/*.Tests.dll")
54 | testDlls
55 | |> xUnit2 (fun p -> p)
56 | )
57 |
58 | "RestorePackages"
59 | ==> "Build"
60 | ==> "Test"
61 | ==> "Default"
62 |
63 | Run "Default"
64 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function run() {
4 | mono "$@"
5 | }
6 |
7 | run .paket/paket.bootstrapper.exe
8 | run .paket/paket.exe restore
9 |
10 | run ./packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx
11 | #run packages/FAKE/tools/FAKE.exe "$@" $FSIARGS build.fsx
--------------------------------------------------------------------------------
/ex1/done/LibAAS.App/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.App/App.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.AppBuilder
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 |
6 | let createApp() =
7 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
8 | (eventStore, execute eventStore)
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.App/App.fsx:
--------------------------------------------------------------------------------
1 | #I "bin/Debug"
2 |
3 | #r "LibAAS.Contracts"
4 | #r "LibAAS.Infrastructure"
5 | #r "LibAAS.Domain"
6 |
7 | #load "App.fs"
8 | open LibAAS.AppBuilder
9 | open LibAAS.Contracts
10 |
11 | let (eventStore,app) = createApp()
12 |
13 | //let itemId = ItemId 4
14 | //let item = ( itemId,
15 | // Book {
16 | // Title = Title "A book"
17 | // Author = Author "A author"})
18 | //
19 | //let qty = Quantity.Create 10
20 | //let aggId = AggregateId 4
21 | //let command = aggId, RegisterInventoryItem (item, qty)
22 | //let result = command |> app
23 | printfn "Result %A" result
24 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.App/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/done/LibAAS.App/Program.fs:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org
2 | // See the 'F# Tutorial' project for more help.
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open System
6 |
7 | []
8 | let main argv =
9 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
10 |
11 | let logSubscriber e =
12 | printfn "Hey ho! Lets go!"
13 | printfn "%A" e
14 | printfn "We went!"
15 |
16 | eventStore.AddSubscriber "logsub" logSubscriber
17 |
18 | let random = new Random()
19 | let newRandomInt() = random.Next()
20 | let newAggId() = AggregateId (newRandomInt())
21 |
22 |
23 | let loanGuid = newRandomInt()
24 | // let userId = UserId (newGuid())
25 | // let itemId = ItemId (newRandomInt())
26 | // let libraryId = LibraryId (newGuid())
27 | // let aggId = AggregateId loanGuid
28 | // let loan = { LoanId = LoanId loanGuid
29 | // UserId = userId
30 | // ItemId = itemId
31 | // LibraryId = libraryId }
32 | //
33 | // let item = ( loan.ItemId,
34 | // Book
35 | // { Title = Title "A book"
36 | // Author = Author "A author"})
37 | //
38 | // let executer = execute eventStore
39 | //
40 | // let newGuid() = Guid.NewGuid()
41 | // let loanId = LoanId (newGuid())
42 | // let commandData = LoanItem(loanId, UserId (newGuid()), ItemId (newGuid()), LibraryId (newGuid()))
43 | // let aggId = AggregateId (Guid.NewGuid())
44 | //
45 | // let result = (aggId, commandData) |> executer
46 | // let returnResult = (aggId, ReturnItem loanId) |> executer
47 |
48 | Console.ReadLine() |> ignore
49 | 0 // return an integer exit code
50 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Contracts/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Contracts.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Contracts/Commands.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Commands
3 |
4 | type CommandData =
5 | | LoanItem of LoanItem
6 | | ReturnItem of ReturnItem
7 | | RegisterInventoryItem of RegisterInventoryItem
8 |
9 | and LoanItem = unit
10 |
11 | and ReturnItem = unit
12 |
13 | and RegisterInventoryItem = {
14 | Item:Item
15 | Quantity:Quantity }
16 |
17 | type Command = AggregateId * CommandData
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Contracts/Events.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Events
3 | open System
4 |
5 | type EventData =
6 | | ItemRegistered of item:Item * Quantity:Quantity
7 |
8 | type Events = AggregateId * EventData list
9 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Contracts/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Types.fs"
5 | open LibAAS.Contracts.Types
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Contracts/Types.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Types
3 | open System
4 |
5 | type AggregateId = AggregateId of int
6 |
7 | type ItemId = ItemId of int
8 | type Title = Title of string
9 | type Author = Author of string
10 | type Book = {Title: Title; Author: Author }
11 | type Quantity = private Quantity of int
12 | with
13 | static member Create x =
14 | if x >= 0 then Quantity x
15 | else raise (exn "Invalid quantity")
16 | type ItemData =
17 | | Book of Book
18 | type Item = ItemId*ItemData
19 |
20 | type Version = int
21 | type Error =
22 | | NotImplemented of string
23 | | VersionConflict of string
24 | | InvalidStateTransition of string
25 | | InvalidState of string
26 | | InvalidItem
27 |
28 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/CommandHandling.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.CommandHandling
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 |
5 | let validateCommand command = command |> ok
6 |
7 | let buildState2 evolveSeed (version, events) =
8 | let evolver res e = bind (evolveSeed.EvolveOne e) res
9 | events |> List.fold evolver (evolveSeed.Init |> ok)
10 |
11 | let stateBuilder evolveSeed getEvents id =
12 | getEvents id >>= buildState2 evolveSeed
13 |
14 | let buildState evolveSeed (aggregateId, version, events, command) =
15 | let evolver res e = bind (evolveSeed.EvolveOne e) res
16 | let state = events |> List.fold evolver (evolveSeed.Init |> ok)
17 | state >>= (fun s -> (aggregateId, version, s, command) |> ok)
18 |
19 | let (|LoanCommand|InventoryCommand|) command =
20 | match command with
21 | | LoanItem _ -> LoanCommand
22 | | ReturnItem _ -> LoanCommand
23 | | RegisterInventoryItem _ -> InventoryCommand
24 |
25 | let commandRouteBuilder stateGetters commandData =
26 | match commandData with
27 | | LoanCommand ->
28 | (buildState Loan.evolveSeed)
29 | >=> (fun (_,_,s,command) -> Loan.executeCommand s stateGetters command)
30 | | InventoryCommand ->
31 | (buildState Inventory.evolveSeed)
32 | >=> (fun (_,_,s,command) -> Inventory.executeCommand s command)
33 |
34 | let executeCommand stateGetters (aggregateId, currentVersion, events, command) =
35 | let (aggId, commandData) = command
36 | (aggregateId, currentVersion, events, command)
37 | |> commandRouteBuilder stateGetters commandData
38 | >>= (fun es -> (aggregateId, currentVersion, es, command) |> ok)
39 |
40 | let getEvents2 eventStore (id) =
41 | eventStore.GetEvents (StreamId id)
42 |
43 | let getEvents eventStore command =
44 | let (AggregateId aggregateId, commandData) = command
45 | eventStore.GetEvents (StreamId aggregateId)
46 | >>= (fun (StreamVersion ver, events) -> (AggregateId aggregateId, ver, events, command) |> ok)
47 |
48 | let saveEvents eventStore (AggregateId aggregateId, expectedVersion, events, command) =
49 | eventStore.SaveEvents (StreamId aggregateId) (StreamVersion expectedVersion) events
50 |
51 | let createGetters eventStore =
52 | {
53 | GetInventoryItem = (fun (ItemId id) -> id |> stateBuilder Inventory.evolveSeed (getEvents2 eventStore))
54 | }
55 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/DomainEntry.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Domain.DomainEntry
2 | open LibAAS.Domain.CommandHandling
3 |
4 | let execute eventStore command =
5 | let stateGetters = createGetters eventStore
6 |
7 | command
8 | |> validateCommand
9 | >>= getEvents eventStore
10 | >>= executeCommand stateGetters
11 | >>= saveEvents eventStore
12 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/DomainTypes.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.DomainTypes
2 |
3 | open LibAAS.Contracts
4 |
5 | type InventoryState =
6 | | ItemInit
7 |
8 | type LoanState =
9 | | LoanInit
10 |
11 | type EvolveOne<'T> = EventData -> 'T -> Result<'T, Error>
12 | type EvolveSeed<'T> =
13 | {
14 | Init: 'T
15 | EvolveOne: EvolveOne<'T>
16 | }
17 |
18 | type InternalDependencies =
19 | {
20 | GetItem: ItemId -> Result
21 | }
22 |
23 | type StateGetters =
24 | {
25 | GetInventoryItem: ItemId -> Result
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/Inventory.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Inventory
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainTypes
5 | open System
6 |
7 | let handleAtInit (id, (command:RegisterInventoryItem)) =
8 | [ItemRegistered(command.Item, command.Quantity)] |> ok
9 |
10 | let executeCommand state command =
11 | match state, command with
12 | | ItemInit, (id, RegisterInventoryItem cmd) -> handleAtInit (id, cmd)
13 | | _ -> InvalidState "Inventory" |> fail
14 |
15 | let evolveAtInit = function
16 | | _ -> raise (exn "Implement me")
17 |
18 | let evolveOne (event:EventData) state =
19 | match state with
20 | | _ -> raise (exn "Implement me")
21 |
22 | let evolveSeed = {Init = ItemInit; EvolveOne = evolveOne}
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Domain/Loan.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Loan
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 | open System
5 |
6 | let handleAtInit stateGetters ((aggId:AggregateId), (commandData:LoanItem)) =
7 | raise (exn "Implement me")
8 |
9 | let handleAtCreated data ((aggId:AggregateId), (commandData:ReturnItem)) =
10 | raise (exn "Implement me")
11 |
12 | let executeCommand state stateGetters command =
13 | match state, command with
14 | | _ -> raise (exn "Implement me")
15 |
16 | let evolveAtInit = function
17 | | _ -> raise (exn "Implement me")
18 |
19 | let evolveAtCreated data = function
20 | | _ -> raise (exn "Implement me")
21 |
22 | let evolveOne (event:EventData) state =
23 | match state with
24 | | _ -> raise (exn "Implement me")
25 |
26 | let evolveSeed = {Init = LoanInit; EvolveOne = evolveOne}
27 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Infrastructure/AgentHelper.fs:
--------------------------------------------------------------------------------
1 | []
2 | module AgentHelper
3 |
4 | type Agent<'T> = MailboxProcessor<'T>
5 | let post (agent:Agent<'T>) message = agent.Post message
6 | let postAsyncReply (agent:Agent<'T>) messageConstr = agent.PostAndAsyncReply(messageConstr)
7 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Infrastructure/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Infrastructure.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Infrastructure/ErrorHandling.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ErrorHandling
3 |
4 | type Result<'TResult, 'TError> =
5 | | Success of 'TResult
6 | | Failure of 'TError
7 |
8 | let bind f = function
9 | | Success y -> f y
10 | | Failure err -> Failure err
11 |
12 | let ok x = Success x
13 | let fail x = Failure x
14 |
15 | let (>>=) result func = bind func result
16 |
17 | let (>=>) f1 f2 = f1 >> (bind f2)
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Infrastructure/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Library1.fs"
5 | open LibAAS.Infrastructure
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/InventoryTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.InventoryTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Tests.Specification
5 | open LibAAS.Tests.TestHelpers
6 | open Xunit
7 |
8 | module ``When add an item to the inventory`` =
9 |
10 | []
11 | let ``the item should be added``() =
12 | let itemIntId = newRandomInt()
13 | let aggId = AggregateId itemIntId
14 | let itemId = ItemId itemIntId
15 | let book = Book {Title = Title "Magic Book"; Author = Author "JRR Tolkien"}
16 | let item = itemId,book
17 | let qty = Quantity.Create 10
18 |
19 | Given defaultPreconditions
20 | |> When (aggId, RegisterInventoryItem { Item = item; Quantity = qty })
21 | |> Then ([ItemRegistered(item, qty)] |> ok)
22 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/LoanTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.LoanTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Domain
5 | open LibAAS.Tests.Specification
6 | open LibAAS.Tests.TestHelpers
7 | open Xunit
8 |
9 | module ``When loaning an item`` =
10 |
11 | let implementME = ()
12 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/Specification.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Tests.Specification
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open EventStore
6 | open Swensen.Unquote
7 |
8 | type Precondition =
9 | { presets: Events list }
10 |
11 | type Specification =
12 | { PreCondition:Precondition
13 | Command: Command option
14 | PostCondition: (Result) option }
15 |
16 | let notImplemented = fun _ -> "Dependency not set for test" |> NotImplemented |> fail
17 |
18 | let defaultPreconditions =
19 | { presets = [] }
20 |
21 | let Given preCondition =
22 | { PreCondition = preCondition
23 | Command = None
24 | PostCondition = None }
25 |
26 | let When command spec = {spec with Command = Some command}
27 |
28 | let Then (postCondition: Result) spec =
29 | let finalSpec = {spec with PostCondition = Some postCondition}
30 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Invalid version when saving")
31 | let executer = execute eventStore
32 |
33 | let savePreConditions preCondition =
34 | preCondition
35 | |> List.iter (fun (AggregateId aggId, events) ->
36 | eventStore.SaveEvents (StreamId aggId) (StreamVersion 0) events |> ignore)
37 |
38 | finalSpec.PreCondition.presets |> savePreConditions
39 | let actual = finalSpec.Command |> Option.get |> executer
40 | let expected = finalSpec.PostCondition |> Option.get
41 |
42 | test <@ actual = expected @>
43 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/TestHelpers.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Tests.TestHelpers
2 | open LibAAS.Contracts.Types
3 | open System
4 |
5 | let random = new Random()
6 | let newRandomInt() = random.Next()
7 | let newAggId() = AggregateId (newRandomInt())
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ex1/done/LibAAS.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.App/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.App/App.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.AppBuilder
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 |
6 | let createApp() =
7 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
8 | (eventStore, execute eventStore)
9 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.App/App.fsx:
--------------------------------------------------------------------------------
1 | #I "bin/Debug"
2 |
3 | #r "LibAAS.Contracts"
4 | #r "LibAAS.Infrastructure"
5 | #r "LibAAS.Domain"
6 |
7 | #load "App.fs"
8 | open LibAAS.AppBuilder
9 | open LibAAS.Contracts
10 |
11 | let (eventStore,app) = createApp()
12 |
13 | //let itemId = ItemId 4
14 | //let item = ( itemId,
15 | // Book {
16 | // Title = Title "A book"
17 | // Author = Author "A author"})
18 | //
19 | //let qty = Quantity.Create 10
20 | //let aggId = AggregateId 4
21 | //let command = aggId, RegisterInventoryItem (item, qty)
22 | //let result = command |> app
23 | printfn "Result %A" result
24 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.App/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/start/LibAAS.App/Program.fs:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org
2 | // See the 'F# Tutorial' project for more help.
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open System
6 |
7 | []
8 | let main argv =
9 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
10 |
11 | let logSubscriber e =
12 | printfn "Hey ho! Lets go!"
13 | printfn "%A" e
14 | printfn "We went!"
15 |
16 | eventStore.AddSubscriber "logsub" logSubscriber
17 |
18 | let random = new Random()
19 | let newRandomInt() = random.Next()
20 | let newAggId() = AggregateId (newRandomInt())
21 |
22 |
23 | let loanGuid = newRandomInt()
24 | // let userId = UserId (newGuid())
25 | // let itemId = ItemId (newRandomInt())
26 | // let libraryId = LibraryId (newGuid())
27 | // let aggId = AggregateId loanGuid
28 | // let loan = { LoanId = LoanId loanGuid
29 | // UserId = userId
30 | // ItemId = itemId
31 | // LibraryId = libraryId }
32 | //
33 | // let item = ( loan.ItemId,
34 | // Book
35 | // { Title = Title "A book"
36 | // Author = Author "A author"})
37 | //
38 | // let executer = execute eventStore
39 | //
40 | // let newGuid() = Guid.NewGuid()
41 | // let loanId = LoanId (newGuid())
42 | // let commandData = LoanItem(loanId, UserId (newGuid()), ItemId (newGuid()), LibraryId (newGuid()))
43 | // let aggId = AggregateId (Guid.NewGuid())
44 | //
45 | // let result = (aggId, commandData) |> executer
46 | // let returnResult = (aggId, ReturnItem loanId) |> executer
47 |
48 | Console.ReadLine() |> ignore
49 | 0 // return an integer exit code
50 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Contracts/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Contracts.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Contracts/Commands.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Commands
3 |
4 | type CommandData =
5 | | LoanItem
6 | | ReturnItem
7 | | RegisterInventoryItem
8 |
9 | and LoanItem = unit
10 | and ReturnItem = unit
11 | and RegisterInventoryItem = unit
12 |
13 | type Command = AggregateId * CommandData
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Contracts/Events.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Events
3 | open System
4 |
5 | type EventData = int
6 |
7 | type Events = AggregateId * EventData list
8 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Contracts/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Types.fs"
5 | open LibAAS.Contracts.Types
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Contracts/Types.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Types
3 | open System
4 |
5 | type AggregateId = AggregateId of int
6 | type ItemId = ItemId of int
7 |
8 | type Version = int
9 |
10 | type Error =
11 | | NotImplemented of string
12 | | VersionConflict of string
13 | | InvalidStateTransition of string
14 | | InvalidState of string
15 | | InvalidItem
16 |
17 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/CommandHandling.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.CommandHandling
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 |
5 | let validateCommand command = command |> ok
6 |
7 | let buildState2 evolveSeed (version, events) =
8 | let evolver res e = bind (evolveSeed.EvolveOne e) res
9 | events |> List.fold evolver (evolveSeed.Init |> ok)
10 |
11 | let stateBuilder evolveSeed getEvents id =
12 | getEvents id >>= buildState2 evolveSeed
13 |
14 | let buildState evolveSeed (aggregateId, version, events, command) =
15 | let evolver res e = bind (evolveSeed.EvolveOne e) res
16 | let state = events |> List.fold evolver (evolveSeed.Init |> ok)
17 | state >>= (fun s -> (aggregateId, version, s, command) |> ok)
18 |
19 | let (|LoanCommand|InventoryCommand|) command =
20 | match command with
21 | | LoanItem _ -> LoanCommand
22 | | ReturnItem _ -> LoanCommand
23 | | RegisterInventoryItem _ -> InventoryCommand
24 |
25 | let commandRouteBuilder stateGetters commandData =
26 | match commandData with
27 | | LoanCommand ->
28 | (buildState Loan.evolveSeed)
29 | >=> (fun (_,_,s,command) -> Loan.executeCommand s stateGetters command)
30 | | InventoryCommand ->
31 | (buildState Inventory.evolveSeed)
32 | >=> (fun (_,_,s,command) -> Inventory.executeCommand s command)
33 |
34 | let executeCommand stateGetters (aggregateId, currentVersion, events, command) =
35 | let (aggId, commandData) = command
36 | (aggregateId, currentVersion, events, command)
37 | |> commandRouteBuilder stateGetters commandData
38 | >>= (fun es -> (aggregateId, currentVersion, es, command) |> ok)
39 |
40 | let getEvents2 eventStore (id) =
41 | eventStore.GetEvents (StreamId id)
42 |
43 | let getEvents eventStore command =
44 | let (AggregateId aggregateId, commandData) = command
45 | eventStore.GetEvents (StreamId aggregateId)
46 | >>= (fun (StreamVersion ver, events) -> (AggregateId aggregateId, ver, events, command) |> ok)
47 |
48 | let saveEvents eventStore (AggregateId aggregateId, expectedVersion, events, command) =
49 | eventStore.SaveEvents (StreamId aggregateId) (StreamVersion expectedVersion) events
50 |
51 | let createGetters eventStore =
52 | {
53 | GetInventoryItem = (fun (ItemId id) -> id |> stateBuilder Inventory.evolveSeed (getEvents2 eventStore))
54 | }
55 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/DomainEntry.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Domain.DomainEntry
2 | open LibAAS.Domain.CommandHandling
3 |
4 | let execute eventStore command =
5 | let stateGetters = createGetters eventStore
6 |
7 | command
8 | |> validateCommand
9 | >>= getEvents eventStore
10 | >>= executeCommand stateGetters
11 | >>= saveEvents eventStore
12 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/DomainTypes.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.DomainTypes
2 |
3 | open LibAAS.Contracts
4 |
5 | type InventoryState =
6 | | ItemInit
7 |
8 | type LoanState =
9 | | LoanInit
10 |
11 | type EvolveOne<'T> = EventData -> 'T -> Result<'T, Error>
12 | type EvolveSeed<'T> =
13 | {
14 | Init: 'T
15 | EvolveOne: EvolveOne<'T>
16 | }
17 |
18 | type InternalDependencies =
19 | {
20 | GetItem: ItemId -> Result
21 | }
22 |
23 | type StateGetters =
24 | {
25 | GetInventoryItem: ItemId -> Result
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/Inventory.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Inventory
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainTypes
5 | open System
6 |
7 | let handleAtInit (id, (command:RegisterInventoryItem)) =
8 | raise (exn "Implement me")
9 |
10 | let executeCommand state command =
11 | match state, command with
12 | | _ -> raise (exn "Implement me")
13 |
14 | let evolveAtInit = function
15 | | _ -> raise (exn "Implement me")
16 |
17 | let evolveOne (event:EventData) state =
18 | match state with
19 | | _ -> raise (exn "Implement me")
20 |
21 | let evolveSeed = {Init = ItemInit; EvolveOne = evolveOne}
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Domain/Loan.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Loan
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 | open System
5 |
6 | let handleAtInit stateGetters ((aggId:AggregateId), (commandData:LoanItem)) =
7 | raise (exn "Implement me")
8 |
9 | let handleAtCreated data ((aggId:AggregateId), (commandData:ReturnItem)) =
10 | raise (exn "Implement me")
11 |
12 | let executeCommand state stateGetters command =
13 | match state, command with
14 | | _ -> raise (exn "Implement me")
15 |
16 | let evolveAtInit = function
17 | | _ -> raise (exn "Implement me")
18 |
19 | let evolveAtCreated data = function
20 | | _ -> raise (exn "Implement me")
21 |
22 | let evolveOne (event:EventData) state =
23 | match state with
24 | | _ -> raise (exn "Implement me")
25 |
26 | let evolveSeed = {Init = LoanInit; EvolveOne = evolveOne}
27 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Infrastructure/AgentHelper.fs:
--------------------------------------------------------------------------------
1 | []
2 | module AgentHelper
3 |
4 | type Agent<'T> = MailboxProcessor<'T>
5 | let post (agent:Agent<'T>) message = agent.Post message
6 | let postAsyncReply (agent:Agent<'T>) messageConstr = agent.PostAndAsyncReply(messageConstr)
7 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Infrastructure/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Infrastructure.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Infrastructure/ErrorHandling.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ErrorHandling
3 |
4 | type Result<'TResult, 'TError> =
5 | | Success of 'TResult
6 | | Failure of 'TError
7 |
8 | let bind f = function
9 | | Success y -> f y
10 | | Failure err -> Failure err
11 |
12 | let ok x = Success x
13 | let fail x = Failure x
14 |
15 | let (>>=) result func = bind func result
16 |
17 | let (>=>) f1 f2 = f1 >> (bind f2)
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Infrastructure/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Library1.fs"
5 | open LibAAS.Infrastructure
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/InventoryTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.InventoryTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Tests.Specification
5 | open LibAAS.Tests.TestHelpers
6 | open Xunit
7 |
8 | module ``When add an item to the inventory`` =
9 |
10 | []
11 | let ``The item should be added``() = ()
12 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/LoanTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.LoanTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Domain
5 | open LibAAS.Tests.Specification
6 | open LibAAS.Tests.TestHelpers
7 | open Xunit
8 |
9 | []
10 | module LoanTestsHelpers = ()
11 |
12 | module ``When loaning an item`` =
13 |
14 | let implementME = ()
15 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/Specification.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Tests.Specification
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open EventStore
6 | open Swensen.Unquote
7 |
8 | type Precondition =
9 | { presets: Events list }
10 |
11 | type Specification =
12 | { PreCondition:Precondition
13 | Command: Command option
14 | PostCondition: (Result) option }
15 |
16 | let notImplemented = fun _ -> "Dependency not set for test" |> NotImplemented |> fail
17 |
18 | let defaultPreconditions =
19 | { presets = [] }
20 |
21 | let Given preCondition =
22 | { PreCondition = preCondition
23 | Command = None
24 | PostCondition = None }
25 |
26 | let When command spec = {spec with Command = Some command}
27 |
28 | let Then (postCondition: Result) spec =
29 | let finalSpec = {spec with PostCondition = Some postCondition}
30 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Invalid version when saving")
31 | let executer = execute eventStore
32 |
33 | let savePreConditions preCondition =
34 | preCondition
35 | |> List.iter (fun (AggregateId aggId, events) ->
36 | eventStore.SaveEvents (StreamId aggId) (StreamVersion 0) events |> ignore)
37 |
38 | finalSpec.PreCondition.presets |> savePreConditions
39 | let actual = finalSpec.Command |> Option.get |> executer
40 | let expected = finalSpec.PostCondition |> Option.get
41 |
42 | test <@ actual = expected @>
43 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/TestHelpers.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Tests.TestHelpers
2 | open LibAAS.Contracts.Types
3 | open System
4 |
5 | let random = new Random()
6 | let newRandomInt() = random.Next()
7 | let newAggId() = AggregateId (newRandomInt())
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ex1/start/LibAAS.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.App/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.App/App.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.AppBuilder
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 |
6 | let createApp() =
7 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
8 | (eventStore, execute eventStore)
9 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.App/App.fsx:
--------------------------------------------------------------------------------
1 | #I "bin/Debug"
2 |
3 | #r "LibAAS.Contracts"
4 | #r "LibAAS.Infrastructure"
5 | #r "LibAAS.Domain"
6 |
7 | #load "App.fs"
8 | open LibAAS.AppBuilder
9 | open LibAAS.Contracts
10 |
11 | let (eventStore,app) = createApp()
12 |
13 | //let itemId = ItemId 4
14 | //let item = ( itemId,
15 | // Book {
16 | // Title = Title "A book"
17 | // Author = Author "A author"})
18 | //
19 | //let qty = Quantity.Create 10
20 | //let aggId = AggregateId 4
21 | //let command = aggId, RegisterInventoryItem (item, qty)
22 | //let result = command |> app
23 | printfn "Result %A" result
24 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.App/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex2/done/LibAAS.App/Program.fs:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org
2 | // See the 'F# Tutorial' project for more help.
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open System
6 |
7 | []
8 | let main argv =
9 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
10 |
11 | let logSubscriber e =
12 | printfn "Hey ho! Lets go!"
13 | printfn "%A" e
14 | printfn "We went!"
15 |
16 | eventStore.AddSubscriber "logsub" logSubscriber
17 |
18 | let random = new Random()
19 | let newRandomInt() = random.Next()
20 | let newAggId() = AggregateId (newRandomInt())
21 |
22 |
23 | let loanGuid = newRandomInt()
24 | // let userId = UserId (newGuid())
25 | // let itemId = ItemId (newRandomInt())
26 | // let libraryId = LibraryId (newGuid())
27 | // let aggId = AggregateId loanGuid
28 | // let loan = { LoanId = LoanId loanGuid
29 | // UserId = userId
30 | // ItemId = itemId
31 | // LibraryId = libraryId }
32 | //
33 | // let item = ( loan.ItemId,
34 | // Book
35 | // { Title = Title "A book"
36 | // Author = Author "A author"})
37 | //
38 | // let executer = execute eventStore
39 | //
40 | // let newGuid() = Guid.NewGuid()
41 | // let loanId = LoanId (newGuid())
42 | // let commandData = LoanItem(loanId, UserId (newGuid()), ItemId (newGuid()), LibraryId (newGuid()))
43 | // let aggId = AggregateId (Guid.NewGuid())
44 | //
45 | // let result = (aggId, commandData) |> executer
46 | // let returnResult = (aggId, ReturnItem loanId) |> executer
47 |
48 | Console.ReadLine() |> ignore
49 | 0 // return an integer exit code
50 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Contracts/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Contracts.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Contracts/Commands.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Commands
3 |
4 | type CommandData =
5 | | LoanItem of LoanItem
6 | | ReturnItem of ReturnItem
7 | | RegisterInventoryItem of RegisterInventoryItem
8 |
9 | and LoanItem = unit
10 |
11 | and ReturnItem = unit
12 |
13 | and RegisterInventoryItem = {
14 | Item:Item
15 | Quantity:Quantity }
16 |
17 |
18 | type Command = AggregateId * CommandData
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Contracts/Events.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Events
3 | open System
4 |
5 | type EventData =
6 | | ItemRegistered of item:Item * Quantity:Quantity
7 |
8 | type Events = AggregateId * EventData list
9 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Contracts/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Types.fs"
5 | open LibAAS.Contracts.Types
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Contracts/Types.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Contracts.Types
3 | open System
4 |
5 | type AggregateId = AggregateId of int
6 |
7 | type ItemId = ItemId of int
8 | type Title = Title of string
9 | type Author = Author of string
10 | type Book = {Title: Title; Author: Author }
11 | type Quantity = private Quantity of int
12 | with
13 | static member Create x =
14 | if x >= 0 then Quantity x
15 | else raise (exn "Invalid quantity")
16 | type ItemData =
17 | | Book of Book
18 | type Item = ItemId*ItemData
19 |
20 | type Version = int
21 | type Error =
22 | | NotImplemented of string
23 | | VersionConflict of string
24 | | InvalidStateTransition of string
25 | | InvalidState of string
26 | | InvalidItem
27 |
28 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/CommandHandling.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.CommandHandling
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 |
5 | let validateCommand command = command |> ok
6 |
7 | let buildState2 evolveSeed (version, events) =
8 | let evolver res e = bind (evolveSeed.EvolveOne e) res
9 | events |> List.fold evolver (evolveSeed.Init |> ok)
10 |
11 | let stateBuilder evolveSeed getEvents id =
12 | getEvents id >>= buildState2 evolveSeed
13 |
14 | let buildState evolveSeed (aggregateId, version, events, command) =
15 | let evolver res e = bind (evolveSeed.EvolveOne e) res
16 | let state = events |> List.fold evolver (evolveSeed.Init |> ok)
17 | state >>= (fun s -> (aggregateId, version, s, command) |> ok)
18 |
19 | let (|LoanCommand|InventoryCommand|) command =
20 | match command with
21 | | LoanItem _ -> LoanCommand
22 | | ReturnItem _ -> LoanCommand
23 | | RegisterInventoryItem _ -> InventoryCommand
24 |
25 | let commandRouteBuilder stateGetters commandData =
26 | match commandData with
27 | | LoanCommand ->
28 | (buildState Loan.evolveSeed)
29 | >=> (fun (_,_,s,command) -> Loan.executeCommand s stateGetters command)
30 | | InventoryCommand ->
31 | (buildState Inventory.evolveSeed)
32 | >=> (fun (_,_,s,command) -> Inventory.executeCommand s command)
33 |
34 | let executeCommand stateGetters (aggregateId, currentVersion, events, command) =
35 | let (aggId, commandData) = command
36 | (aggregateId, currentVersion, events, command)
37 | |> commandRouteBuilder stateGetters commandData
38 | >>= (fun es -> (aggregateId, currentVersion, es, command) |> ok)
39 |
40 | let getEvents2 eventStore (id) =
41 | eventStore.GetEvents (StreamId id)
42 |
43 | let getEvents eventStore command =
44 | let (AggregateId aggregateId, commandData) = command
45 | eventStore.GetEvents (StreamId aggregateId)
46 | >>= (fun (StreamVersion ver, events) -> (AggregateId aggregateId, ver, events, command) |> ok)
47 |
48 | let saveEvents eventStore (AggregateId aggregateId, expectedVersion, events, command) =
49 | eventStore.SaveEvents (StreamId aggregateId) (StreamVersion expectedVersion) events
50 |
51 | let createGetters eventStore =
52 | {
53 | GetInventoryItem = (fun (ItemId id) -> id |> stateBuilder Inventory.evolveSeed (getEvents2 eventStore))
54 | }
55 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/DomainEntry.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Domain.DomainEntry
2 | open LibAAS.Domain.CommandHandling
3 |
4 | let execute eventStore command =
5 | let stateGetters = createGetters eventStore
6 |
7 | command
8 | |> validateCommand
9 | >>= getEvents eventStore
10 | >>= executeCommand stateGetters
11 | >>= saveEvents eventStore
12 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/DomainTypes.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.DomainTypes
2 |
3 | open LibAAS.Contracts
4 |
5 | type InventoryState =
6 | | ItemInit
7 | | ItemInStock of item:Item*quantity:Quantity
8 |
9 | type LoanState =
10 | | LoanInit
11 |
12 | type EvolveOne<'T> = EventData -> 'T -> Result<'T, Error>
13 | type EvolveSeed<'T> =
14 | {
15 | Init: 'T
16 | EvolveOne: EvolveOne<'T>
17 | }
18 |
19 | type InternalDependencies =
20 | {
21 | GetItem: ItemId -> Result
22 | }
23 |
24 | type StateGetters =
25 | {
26 | GetInventoryItem: ItemId -> Result
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/Inventory.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Inventory
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainTypes
5 | open System
6 |
7 | let handleAtInit (id, (command:RegisterInventoryItem)) =
8 | [ItemRegistered(command.Item, command.Quantity)] |> ok
9 |
10 | let executeCommand state command =
11 | match state, command with
12 | | ItemInit, (id, RegisterInventoryItem cmd) -> handleAtInit (id, cmd)
13 | | _ -> InvalidState "Inventory" |> fail
14 |
15 | let evolveAtInit = function
16 | | ItemRegistered(item, quantity) -> ItemInStock (item, quantity) |> ok
17 |
18 | let evolveOne (event:EventData) state =
19 | match state with
20 | | ItemInit -> evolveAtInit event
21 |
22 | let evolveSeed = {Init = ItemInit; EvolveOne = evolveOne}
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Domain/Loan.fs:
--------------------------------------------------------------------------------
1 | module internal LibAAS.Domain.Loan
2 | open LibAAS.Contracts
3 | open LibAAS.Domain.DomainTypes
4 | open System
5 |
6 | let handleAtInit stateGetters ((aggId:AggregateId), (commandData:LoanItem)) =
7 | raise (exn "Implement me")
8 |
9 | let handleAtCreated data ((aggId:AggregateId), (commandData:ReturnItem)) =
10 | raise (exn "Implement me")
11 |
12 | let executeCommand state stateGetters command =
13 | match state, command with
14 | | _ -> raise (exn "Implement me")
15 |
16 | let evolveAtInit = function
17 | | _ -> raise (exn "Implement me")
18 |
19 | let evolveAtCreated data = function
20 | | _ -> raise (exn "Implement me")
21 |
22 | let evolveOne (event:EventData) state =
23 | match state with
24 | | _ -> raise (exn "Implement me")
25 |
26 | let evolveSeed = {Init = LoanInit; EvolveOne = evolveOne}
27 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Infrastructure/AgentHelper.fs:
--------------------------------------------------------------------------------
1 | []
2 | module AgentHelper
3 |
4 | type Agent<'T> = MailboxProcessor<'T>
5 | let post (agent:Agent<'T>) message = agent.Post message
6 | let postAsyncReply (agent:Agent<'T>) messageConstr = agent.PostAndAsyncReply(messageConstr)
7 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Infrastructure/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Infrastructure.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Infrastructure/ErrorHandling.fs:
--------------------------------------------------------------------------------
1 | []
2 | module ErrorHandling
3 |
4 | type Result<'TResult, 'TError> =
5 | | Success of 'TResult
6 | | Failure of 'TError
7 |
8 | let bind f = function
9 | | Success y -> f y
10 | | Failure err -> Failure err
11 |
12 | let ok x = Success x
13 | let fail x = Failure x
14 |
15 | let (>>=) result func = bind func result
16 |
17 | let (>=>) f1 f2 = f1 >> (bind f2)
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Infrastructure/Script.fsx:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
2 | // for more guidance on F# programming.
3 |
4 | #load "Library1.fs"
5 | open LibAAS.Infrastructure
6 |
7 | // Define your library scripting code here
8 |
9 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | []
38 | []
39 |
40 | do
41 | ()
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/InventoryTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.InventoryTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Tests.Specification
5 | open LibAAS.Tests.TestHelpers
6 | open Xunit
7 |
8 | module ``When add an item to the inventory`` =
9 |
10 | []
11 | let ``the item should be added``() =
12 | let itemIntId = newRandomInt()
13 | let aggId = AggregateId itemIntId
14 | let itemId = ItemId itemIntId
15 | let book = Book {Title = Title "Magic Book"; Author = Author "JRR Tolkien"}
16 | let item = itemId,book
17 | let qty = Quantity.Create 10
18 |
19 | Given defaultPreconditions
20 | |> When (aggId, RegisterInventoryItem { Item = item; Quantity = qty })
21 | |> Then ([ItemRegistered(item, qty)] |> ok)
22 |
23 | []
24 | let ``The item should not be added if the id is not unique``() =
25 | let itemIntId = newRandomInt()
26 | let aggId = AggregateId itemIntId
27 | let itemId = ItemId itemIntId
28 | let book = Book {Title = Title "Magic Book"; Author = Author "JRR Tolkien"}
29 | let item = itemId,book
30 | let qty = Quantity.Create 10
31 |
32 | Given {
33 | defaultPreconditions
34 | with
35 | presets = [aggId, [ItemRegistered(item, qty)]] }
36 | |> When (aggId, RegisterInventoryItem { Item = item; Quantity = qty })
37 | |> Then (InvalidState "Inventory" |> fail)
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/LoanTests.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.Tests.LoanTests
2 | open System
3 | open LibAAS.Contracts
4 | open LibAAS.Domain
5 | open LibAAS.Tests.Specification
6 | open LibAAS.Tests.TestHelpers
7 | open Xunit
8 |
9 | module ``When loaning an item`` =
10 |
11 | let implementME = ()
12 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/Specification.fs:
--------------------------------------------------------------------------------
1 | []
2 | module LibAAS.Tests.Specification
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 | open EventStore
6 | open Swensen.Unquote
7 |
8 | type Precondition =
9 | { presets: Events list }
10 |
11 | type Specification =
12 | { PreCondition:Precondition
13 | Command: Command option
14 | PostCondition: (Result) option }
15 |
16 | let notImplemented = fun _ -> "Dependency not set for test" |> NotImplemented |> fail
17 |
18 | let defaultPreconditions =
19 | { presets = [] }
20 |
21 | let Given preCondition =
22 | { PreCondition = preCondition
23 | Command = None
24 | PostCondition = None }
25 |
26 | let When command spec = {spec with Command = Some command}
27 |
28 | let Then (postCondition: Result) spec =
29 | let finalSpec = {spec with PostCondition = Some postCondition}
30 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Invalid version when saving")
31 | let executer = execute eventStore
32 |
33 | let savePreConditions preCondition =
34 | preCondition
35 | |> List.iter (fun (AggregateId aggId, events) ->
36 | eventStore.SaveEvents (StreamId aggId) (StreamVersion 0) events |> ignore)
37 |
38 | finalSpec.PreCondition.presets |> savePreConditions
39 | let actual = finalSpec.Command |> Option.get |> executer
40 | let expected = finalSpec.PostCondition |> Option.get
41 |
42 | test <@ actual = expected @>
43 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/TestHelpers.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.Tests.TestHelpers
2 | open LibAAS.Contracts.Types
3 | open System
4 |
5 | let random = new Random()
6 | let newRandomInt() = random.Next()
7 | let newAggId() = AggregateId (newRandomInt())
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ex2/done/LibAAS.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/ex2/start/LibAAS.App/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ex2/start/LibAAS.App/App.fs:
--------------------------------------------------------------------------------
1 | module LibAAS.AppBuilder
2 |
3 | open LibAAS.Contracts
4 | open LibAAS.Domain.DomainEntry
5 |
6 | let createApp() =
7 | let eventStore = createInMemoryEventStore (Error.VersionConflict "Version conflict")
8 | (eventStore, execute eventStore)
9 |
--------------------------------------------------------------------------------
/ex2/start/LibAAS.App/App.fsx:
--------------------------------------------------------------------------------
1 | #I "bin/Debug"
2 |
3 | #r "LibAAS.Contracts"
4 | #r "LibAAS.Infrastructure"
5 | #r "LibAAS.Domain"
6 |
7 | #load "App.fs"
8 | open LibAAS.AppBuilder
9 | open LibAAS.Contracts
10 |
11 | let (eventStore,app) = createApp()
12 |
13 | //let itemId = ItemId 4
14 | //let item = ( itemId,
15 | // Book {
16 | // Title = Title "A book"
17 | // Author = Author "A author"})
18 | //
19 | //let qty = Quantity.Create 10
20 | //let aggId = AggregateId 4
21 | //let command = aggId, RegisterInventoryItem (item, qty)
22 | //let result = command |> app
23 | printfn "Result %A" result
24 |
--------------------------------------------------------------------------------
/ex2/start/LibAAS.App/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace LibAAS.App.AssemblyInfo
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | []
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | []
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // []
37 | [