Skip to content

Instantly share code, notes, and snippets.

@CallumVass
Last active February 3, 2021 19:04
Show Gist options
  • Save CallumVass/a7aef78004891b8c8be8d8d1fd0b6359 to your computer and use it in GitHub Desktop.
Save CallumVass/a7aef78004891b8c8be8d8d1fd0b6359 to your computer and use it in GitHub Desktop.
open System
open System.Collections.Generic
type ProductShipped =
{ Sku: string
Quantity: int
DateTime: DateTime }
type ProductReceived =
{ Sku: string
Quantity: int
DateTime: DateTime }
type InventoryAdjusted =
{ Sku: string
Quantity: int
Reason: string
DateTime: DateTime }
type DomainError =
| NotEnoughStock
| InvalidProductAdjustment
type Event =
| ProductShipped of ProductShipped
| ProductReceived of ProductReceived
| InventoryAdjusted of InventoryAdjusted
type CurrentState = { QuantityOnHand: int }
type WarehouseProduct(sku) =
let events = List<Event>()
let mutable currentState = { QuantityOnHand = 0 }
member __.Sku = sku
member __.Apply(evt: ProductShipped) =
let newQuantity =
currentState.QuantityOnHand - evt.Quantity
currentState <-
{ currentState with
QuantityOnHand = newQuantity }
member __.Apply(evt: ProductReceived) =
let newQuantity =
currentState.QuantityOnHand + evt.Quantity
currentState <-
{ currentState with
QuantityOnHand = newQuantity }
member __.Apply(evt: InventoryAdjusted) =
let newQuantity =
currentState.QuantityOnHand + evt.Quantity
currentState <-
{ currentState with
QuantityOnHand = newQuantity }
member this.AddEvent evt =
match evt with
| ProductShipped shipProduct -> this.Apply shipProduct
| ProductReceived receiveProduct -> this.Apply receiveProduct
| InventoryAdjusted adjustInventory -> this.Apply adjustInventory
events.Add evt
member __.GetEvents() = events
member this.ShipProduct quantity =
if quantity > currentState.QuantityOnHand then
Error NotEnoughStock
else
let productShipped: ProductShipped =
{ Sku = this.Sku
Quantity = quantity
DateTime = DateTime.UtcNow }
this.AddEvent(ProductShipped productShipped)
Ok()
member this.ReceiveProduct quantity =
let productReceived: ProductReceived =
{ Sku = this.Sku
Quantity = quantity
DateTime = DateTime.UtcNow }
this.AddEvent(ProductReceived productReceived)
member this.AdjustInventory quantity reason =
if currentState.QuantityOnHand + quantity < 0 then
Error InvalidProductAdjustment
else
let inventoryAdjusted: InventoryAdjusted =
{ Sku = this.Sku
Quantity = quantity
Reason = reason
DateTime = DateTime.UtcNow }
this.AddEvent(InventoryAdjusted inventoryAdjusted)
Ok()
type Warehouse() =
let inMemoryStreams = Dictionary<string, IList<Event>>()
member __.Get sku =
let product = WarehouseProduct(sku)
if inMemoryStreams.ContainsKey sku then
inMemoryStreams.Item(sku)
|> Seq.iter (product.AddEvent)
product
member __.Save(product: WarehouseProduct) =
inMemoryStreams.Item(product.Sku) <- product.GetEvents()
()
[<EntryPoint>]
let main argv =
let repository = Warehouse()
let sku = "PROD001"
let product = repository.Get sku
product.ReceiveProduct 5
let shipResult = product.ShipProduct 4
let adjustResult =
product.AdjustInventory 10 "Found in Store"
match shipResult with
| Ok () -> printfn "Product shipped"
| Error e -> printfn "Error shipping product: %A" e
match adjustResult with
| Ok () -> printfn "Inventory adjusted"
| Error e -> printfn "Error adjusting stock: %A" e
repository.Save product
let product = repository.Get sku
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment