Skip to content

Commit

Permalink
DAL, composition root, console launcher (#1)
Browse files Browse the repository at this point in the history
* add data access project

* data access layer init create

* refactoring

* composition root added

* console launcher
  • Loading branch information
atsapura committed Jun 11, 2019
1 parent b643a50 commit 265056f
Show file tree
Hide file tree
Showing 33 changed files with 1,149 additions and 66 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
[Oo]bj
[Dd]ebug
[Rr]elease
*.user
*.suo
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.4.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\CardManagement.Common\CardManagement.Common.fsproj" />
<ProjectReference Include="..\..\CardManagement.Data\CardManagement.Data.fsproj" />
<ProjectReference Include="..\..\CardManagement\CardManagement.fsproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.6.2" />
</ItemGroup>
Expand Down

This file was deleted.

7 changes: 7 additions & 0 deletions CardManagement.Api/CardManagement.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"MongoDB": {
"Database": "CardDb",
"Host": "localhost",
"Port": 27017,
"User": "root",
"Password": "example"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
Expand Down
4 changes: 3 additions & 1 deletion CardManagement.Common/CardManagement.Common.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="Country.fs" />
<Compile Include="Common.fs" />
<Compile Include="Errors.fs" />
<Compile Include="ErrorMessages.fs" />
<Compile Include="Country.fs" />
<Compile Include="CommonTypes.fs" />
</ItemGroup>

Expand Down
16 changes: 16 additions & 0 deletions CardManagement.Common/Common.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace CardManagement.Common

[<AutoOpen>]
module Common =
let inline (|HasLength|) x =
fun () -> (^a: (member Length: int) x)

let inline (|HasCount|) x =
fun () -> (^a: (member Count: int) x)

let inline length (HasLength f) = f()

let inline isNullOrEmpty arg =
if arg = null || (length arg) = 0 then true
else false

10 changes: 6 additions & 4 deletions CardManagement.Common/CommonTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module CommonTypes =
type Month =
| January | February | March | April | May | June | July | August | September | October | November | December
with
member this.toNumber() =
member this.ToNumber() =
match this with
| January -> 1us
| February -> 2us
Expand All @@ -29,7 +29,7 @@ module CommonTypes =
| October -> 10us
| November -> 11us
| December -> 12us
static member ofNumber field n =
static member create field n =
match n with
| 1us -> January |> Ok
| 2us -> February |> Ok
Expand All @@ -54,7 +54,7 @@ module CommonTypes =
else validationError field "Year must be between 2019 and 2050"


type LetterString = LetterString of string
type LetterString = private LetterString of string
with
member this.Value = match this with LetterString s -> s
static member create field str =
Expand All @@ -78,7 +78,7 @@ module CommonTypes =
match str with
| (""|null) -> validationError field "Postal code can't be empty"
| str ->
if postalCodeRegex.IsMatch(str)
if postalCodeRegex.IsMatch(str) |> not
then validationError field "postal code must contain 5 or 6 digits and nothing else"
else PostalCode str |> Ok

Expand All @@ -88,3 +88,5 @@ module CommonTypes =
PostalCode: PostalCode
AddressLine1: string
AddressLine2: string }

type nil<'a when 'a: struct and 'a: (new: unit-> 'a) and 'a:> System.ValueType> = System.Nullable<'a>
22 changes: 22 additions & 0 deletions CardManagement.Common/Country.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
namespace CardManagement.Common

[<AutoOpen>]
module CountryModule =
open Microsoft.FSharp.Reflection
open Errors

type Country =
| Afghanistan
| Albania
Expand Down Expand Up @@ -197,3 +202,20 @@
| Yemen
| Zambia
| Zimbabwe

let (=~) str1 str2 = System.String.Equals(str1, str2, System.StringComparison.InvariantCultureIgnoreCase)

let tryParseEmptyDUCase<'DU> str =
if FSharpType.IsUnion typeof<'DU> |> not then None
else
match str with
| null | "" -> None
| str ->
FSharpType.GetUnionCases typeof<'DU>
|> Array.tryFind (fun c -> c.Name =~ str && (c.GetFields() |> Array.isEmpty))
|> Option.map (fun case -> FSharpValue.MakeUnion(case, [||]) :?> 'DU)

let parseCountry country =
match tryParseEmptyDUCase<Country> country with
| Some country -> Ok country
| None -> Error { FieldPath = "country"; Message = sprintf "Country %s is unknown" country}
30 changes: 30 additions & 0 deletions CardManagement.Common/ErrorMessages.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace CardManagement.Common

module ErrorMessages =

open Errors

let private entityDescription = sprintf "[%s] entity with id [%s]"

let dataRelatedErrorMessage =
function
| EntityAlreadyExists (name, id) -> entityDescription name id |> sprintf "%s already exists."
| EntityNotFound (name, id) -> entityDescription name id |> sprintf "%s was not found."
| EntityIsInUse (name, id) -> entityDescription name id |> sprintf "%s is in use."
| UpdateError (name, id, message) ->
message |> (entityDescription name id |> sprintf "%s failed to update. Details:\n%s")
| InvalidDbData { EntityName = name; EntityId = id; Message = message } ->
message |> (entityDescription name id |> sprintf "%s is invalid. Details:\n%s")

let validationMessage { FieldPath = path; Message = message } =
sprintf "Field [%s] is invalid. Message: %s" path message

let operationNotAllowedMessage { Operation = op; Reason = reason } =
sprintf "Operation [%s] is not allowed. Reason: %s" op reason

let errorMessage error =
match error with
| ValidationError v -> validationMessage v
| OperationNotAllowed o -> operationNotAllowedMessage o
| DataError d -> dataRelatedErrorMessage d
| Bug b -> sprintf "Oops, something went wrong."
42 changes: 34 additions & 8 deletions CardManagement.Common/Errors.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,27 @@ module Errors =
{ Operation: string
Reason: string }

type Panic =
| Exc of Exception
| PanicMessage of message: string * source: string
type InvalidDbDataError =
{ EntityName: string
EntityId: string
Message: string }

type DataRelatedError =
| EntityAlreadyExists of entityName: string * id: string
| EntityNotFound of entityName: string * id: string
| EntityIsInUse of entityName: string
| UpdateError of entityName:string * message:string
| Panic of Panic
| EntityIsInUse of entityName: string * id: string
| UpdateError of entityName:string * id: string * message:string
| InvalidDbData of InvalidDbDataError

type Bug =
| Exn of Exception
| InvalidDbDataError of InvalidDbDataError

type Error =
| ValidationError of ValidationError
| OperationNotAllowed of OperationNotAllowedError
| DataError of DataRelatedError
| Bug of Panic
| Bug of Bug

let validationError fieldPath message = { FieldPath = fieldPath; Message = message } |> Error

Expand All @@ -66,7 +72,7 @@ module Errors =

let expectDataRelatedError result =
match result with
| Error (Panic ex) -> Bug ex |> Error
| Error (InvalidDbData err) -> InvalidDbDataError err |> Bug |> Error
| result -> Result.mapError DataError result

let expectDataRelatedErrorAsync asyncResult =
Expand All @@ -84,3 +90,23 @@ module Errors =
type ValidationResult<'a> = Result<'a, ValidationError>
type IoResult<'a> = AsyncResult<'a, DataRelatedError>
type PipelineResult<'a> = AsyncResult<'a, Error>

[<RequireQualifiedAccess>]
module Result =

let combine results =
let rec loop acc results =
match results with
| [] -> acc
| result :: tail ->
match result with
| Error e -> Error e
| Ok ok ->
let acc = Result.map (fun oks -> ok :: oks) acc
loop acc tail
loop (Ok []) results

let ofOption err opt =
match opt with
| Some v -> Ok v
| None -> Error err
34 changes: 34 additions & 0 deletions CardManagement.Console/CardManagement.Console.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Compile Include="Program.fs" />
</ItemGroup>

<ItemGroup />

<ItemGroup>
<ProjectReference Include="..\CardManagement.Common\CardManagement.Common.fsproj" />
<ProjectReference Include="..\CardManagement.Data\CardManagement.Data.fsproj" />
<ProjectReference Include="..\CardManagement.Infrastructure\CardManagement.Infrastructure.fsproj" />
<ProjectReference Include="..\CardManagement\CardManagement.fsproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.6.2" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions CardManagement.Console/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Learn more about F# at http://fsharp.org

open System

open CardManagement.CardDomainCommandModels
open CardManagement.Infrastructure

[<EntryPoint>]
let main argv =
let createUserCmd =
{ CreateUserCommandModel.Name = "Roman"
Address =
{ CreateAddressCommandModel.Country = "Russia"
City = "SaintPetersburg"
PostalCode = "12345"
AddressLine1 = "Rubinstein st. 13"
AddressLine2 = "ap. 1" } }

printfn "creating user:\n%A\n" createUserCmd
let user = CompositionRoot.createUser createUserCmd |> Async.RunSynchronously
printfn "user created:\n%A\n" user
match user with
| Ok user ->
printfn "getting user with id %A" user.Id
let user = CompositionRoot.getUser user.Id |> Async.RunSynchronously
printfn "finished getting user:\n%A" user
| Error e -> printfn "Error occured:\n%A" e
Console.ReadLine() |> ignore
0 // return an integer exit code
9 changes: 9 additions & 0 deletions CardManagement.Console/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
15 changes: 15 additions & 0 deletions CardManagement.Console/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"MongoDB": {
"Database": "CardDb",
"Host": "localhost",
"Port": 27017,
"User": "root",
"Password": "example"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
Loading

0 comments on commit 265056f

Please sign in to comment.