From 2c707eb6e5804e1cccaeb59f75515d74a30d4f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carsten=20K=C3=B6nig?= Date: Mon, 20 Oct 2014 09:49:16 +0200 Subject: [PATCH] angepasstes Readmodel aus Eventsourcing --- GrauhundReisen.DomainFunktional/Booking.fs | 3 + .../GrauhundReisen.ReadModel.csproj | 1 - .../Repositories/Bookings.cs | 69 --------------- GrauhundReisen.ReadModelFunktional/Booking.fs | 83 +++++-------------- .../FileKeyValueStore.fs | 27 ++++++ .../GrauhundReisen.ReadModelFunktional.fsproj | 46 +++++----- .../packages.config | 4 + GrauhundReisen.WebPortal/Boostrapper.cs | 6 +- .../Controller/Booking.cs | 6 +- .../GrauhundReisen.WebPortal.csproj | 1 + 10 files changed, 87 insertions(+), 159 deletions(-) delete mode 100644 GrauhundReisen.ReadModel/Repositories/Bookings.cs create mode 100644 GrauhundReisen.ReadModelFunktional/FileKeyValueStore.fs create mode 100644 GrauhundReisen.ReadModelFunktional/packages.config diff --git a/GrauhundReisen.DomainFunktional/Booking.fs b/GrauhundReisen.DomainFunktional/Booking.fs index 25cd8ca..b0439f0 100644 --- a/GrauhundReisen.DomainFunktional/Booking.fs +++ b/GrauhundReisen.DomainFunktional/Booking.fs @@ -132,6 +132,9 @@ module Booking = let registerEventHandler handler (Service service) = service |> EventStore.subscribe handler + let registerReadmodel rm (Service service) = + EventStore.registerReadmodel service rm + let order (bookingId, destination, creditCard, email, name) (Service service) = let event = create bookingId name email creditCard destination diff --git a/GrauhundReisen.ReadModel/GrauhundReisen.ReadModel.csproj b/GrauhundReisen.ReadModel/GrauhundReisen.ReadModel.csproj index 87e2d7c..54f864f 100644 --- a/GrauhundReisen.ReadModel/GrauhundReisen.ReadModel.csproj +++ b/GrauhundReisen.ReadModel/GrauhundReisen.ReadModel.csproj @@ -39,7 +39,6 @@ - diff --git a/GrauhundReisen.ReadModel/Repositories/Bookings.cs b/GrauhundReisen.ReadModel/Repositories/Bookings.cs deleted file mode 100644 index aef204d..0000000 --- a/GrauhundReisen.ReadModel/Repositories/Bookings.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.IO; -using GrauhundReisen.ReadModelFunktional; -using Microsoft.FSharp.Core; -using Newtonsoft.Json; - -namespace GrauhundReisen.ReadModel.Repositories -{ - public class Bookings : Booking.IRepository - { - readonly String _bookingsPath; - - public Bookings (string connectionString) - { - _bookingsPath = connectionString; - } - - public Booking.T GetBookingBy(String bookingId){ - - return ReadBookingFromFile(bookingId); - } - - public Booking.T ReadBookingFromFile(string bookingId) - { - var bookingPath = Path.Combine (_bookingsPath, bookingId); - - if (!File.Exists(bookingPath)) - return null; - - var bookingAsString = File.ReadAllText (bookingPath); - - var booking = JsonConvert.DeserializeObject(bookingAsString); - - return booking; - } - - public void SaveBookingAsFile(Booking.T booking) - { - var savePath = Path.Combine(_bookingsPath, booking.Id); - var bookingAsJson = JsonConvert.SerializeObject(booking); - - File.WriteAllText(savePath, bookingAsJson); - } - - public void DeleteBooking(String bookingId) - { - var bookingPath = Path.Combine(_bookingsPath, bookingId); - - File.Delete(bookingPath); - } - - public FSharpOption GetBy(string id) - { - var rm = ReadBookingFromFile(id); - if (rm == null) return Booking.none; - return Booking.some(rm); - } - - public void Delete(string id) - { - DeleteBooking(id); - } - - public void Save(Booking.T booking) - { - SaveBookingAsFile(booking); - } - } -} \ No newline at end of file diff --git a/GrauhundReisen.ReadModelFunktional/Booking.fs b/GrauhundReisen.ReadModelFunktional/Booking.fs index f21d7d5..261a910 100644 --- a/GrauhundReisen.ReadModelFunktional/Booking.fs +++ b/GrauhundReisen.ReadModelFunktional/Booking.fs @@ -15,17 +15,7 @@ module Booking = Id : string } - let empty = - { CreditCardNumber = "" - CreditCardType = "" - Destination = "" - EMail = "" - FirstName = "" - LastName = "" - Id = string GrauhundReisen.DomainFunktional.Booking.BookingId.Empty - } - - let create (id, first, last, email, credType, credNr, dest) = + let internal create (id, first, last, email, credType, credNr, dest) = { CreditCardNumber = credNr CreditCardType = credType Destination = dest @@ -35,54 +25,23 @@ module Booking = Id = id } - let none : T option = None - - let some t : T option = Some t - - type IRepository = - abstract GetBy : Id -> T option - abstract Delete : Id -> unit - abstract Save : T -> unit - - module Projections = - open EventSourcing.Projection - open GrauhundReisen.DomainFunktional.Booking - open GrauhundReisen.DomainFunktional.Booking.Projections - - let booking = - EventSourcing.Projection.create - empty - (fun b ev -> - match ev with - | Events.Ordered (GrauhundReisen.DomainFunktional.Booking.Booking (id, order)) -> - let (ct,cn) = GrauhundReisen.DomainFunktional.Booking.Convert.fromCreditCard order.CreditCard - let (GrauhundReisen.DomainFunktional.Booking.Email email) = order.Email - { b with Id = string id - CreditCardType = ct - CreditCardNumber = cn - Destination = order.Destination - EMail = email - FirstName = order.Name.Givenname - LastName = order.Name.Surname - } - | Events.EmailChanged (GrauhundReisen.DomainFunktional.Booking.Email email) -> - { b with EMail = email } - | Events.CreditCardChanged creditCard -> - let (ct,cn) = GrauhundReisen.DomainFunktional.Booking.Convert.fromCreditCard creditCard - { b with CreditCardType = ct - CreditCardNumber = cn - }) - - let eventHandler (repo : IRepository) - (id : GrauhundReisen.DomainFunktional.Booking.BookingId, event : Events) = - let readModelFrom = - match repo.GetBy (id.ToString()) with - | Some rm -> rm - | None -> empty - // das gefällt mir so noch nicht - das ist die Schwäche des "Zwischenschritts/Typs" - let readModelTo = EventSourcing.Projection.foldFrom Projections.booking readModelFrom (Seq.singleton event) - repo.Delete (id.ToString()) - repo.Save readModelTo - - let RegisterAt(repo : IRepository, service : GrauhundReisen.DomainFunktional.Booking.Service.T) = - service |> GrauhundReisen.DomainFunktional.Booking.Service.registerEventHandler (eventHandler repo) \ No newline at end of file + type ReadModel internal (load) = + member __.Load(key) = load key + + let createFileIO path = + let proj = + GrauhundReisen.DomainFunktional.Booking.Projections.booking + |> EventSourcing.Projection.map + (fun (GrauhundReisen.DomainFunktional.Booking.Booking (id,order)) -> + let (GrauhundReisen.DomainFunktional.Booking.Email email) = order.Email + let (ct, cn) = GrauhundReisen.DomainFunktional.Booking.Convert.fromCreditCard order.CreditCard + create (string id, order.Name.Givenname, order.Name.Surname, email, ct, cn, order.Destination)) + EventSourcing.ReadModel.create + (FileKeyValueStore.createFileStore path) + proj + (fun id _ -> id) + + let createReadModel path = + let rm = createFileIO path + ReadModel (fun key -> + EventSourcing.ReadModel.load rm (EventSourcing.EntityId.Parse key)) \ No newline at end of file diff --git a/GrauhundReisen.ReadModelFunktional/FileKeyValueStore.fs b/GrauhundReisen.ReadModelFunktional/FileKeyValueStore.fs new file mode 100644 index 0000000..08be287 --- /dev/null +++ b/GrauhundReisen.ReadModelFunktional/FileKeyValueStore.fs @@ -0,0 +1,27 @@ +namespace GrauhundReisen.ReadModelFunktional + +open EventSourcing +open System.IO +open Newtonsoft.Json + +module FileKeyValueStore = + + let createFileStore<'key,'value> (path : string) : IKeyValueStore<'key,'value> = + let readFromFile key = + try + let path = Path.Combine (path, key.ToString()) + if not <| File.Exists path then None else + let content = File.ReadAllText path + JsonConvert.DeserializeObject<'value> content + |> Some + with + | _ -> None + let writeToFile (key, value) = + let path = Path.Combine(path, key.ToString()) + let json = JsonConvert.SerializeObject value + if File.Exists path then File.Delete path else + File.WriteAllText(path, json) + { new IKeyValueStore<'key,'value> with + member __.Read key = readFromFile key + member __.Save key value = writeToFile (key, value) + } \ No newline at end of file diff --git a/GrauhundReisen.ReadModelFunktional/GrauhundReisen.ReadModelFunktional.fsproj b/GrauhundReisen.ReadModelFunktional/GrauhundReisen.ReadModelFunktional.fsproj index d5ff18c..4080543 100644 --- a/GrauhundReisen.ReadModelFunktional/GrauhundReisen.ReadModelFunktional.fsproj +++ b/GrauhundReisen.ReadModelFunktional/GrauhundReisen.ReadModelFunktional.fsproj @@ -32,6 +32,27 @@ 3 bin\Release\GrauhundReisen.ReadModelFunktional.XML + + 11 + + + + + $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets + + + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets + + + + + + + + + ..\packages\EventSourcing.dll @@ -40,36 +61,19 @@ True + + ..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll + True + - - - - - GrauhundReisen.DomainFunktional {a7f6157d-cb71-4c47-baac-f50a810690e5} True - - 11 - - - - - $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets - - - - - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets - - - -