Use FSharpLu for JSON serialization (#24)

This commit is contained in:
Daniel J. Summers 2019-02-23 13:59:32 -06:00
parent 8995097d68
commit d738321dc0
5 changed files with 24 additions and 17 deletions

View File

@ -2,14 +2,7 @@
open FSharp.Control.Tasks.V2.ContextInsensitive
open Microsoft.EntityFrameworkCore
/// Helpers for this file
[<AutoOpen>]
module private Helpers =
/// Convert any item to an option (Option.ofObj does not work for non-nullable types)
let toOption<'T> (x : 'T) = match box x with null -> None | _ -> Some x
open Microsoft.FSharpLu
/// Entities for use in the data model for myPrayerJournal
[<AutoOpen>]
@ -247,7 +240,7 @@ type AppDbContext (opts : DbContextOptions<AppDbContext>) =
member this.TryRequestById reqId userId =
task {
let! req = this.Requests.AsNoTracking().FirstOrDefaultAsync(fun r -> r.requestId = reqId && r.userId = userId)
return toOption req
return Option.fromObject req
}
/// Retrieve notes for a request by its ID and user ID
@ -262,7 +255,7 @@ type AppDbContext (opts : DbContextOptions<AppDbContext>) =
member this.TryJournalById reqId userId =
task {
let! req = this.Journal.FirstOrDefaultAsync(fun r -> r.requestId = reqId && r.userId = userId)
return toOption req
return Option.fromObject req
}
/// Retrieve a request, including its history and notes, by its ID and user ID
@ -275,7 +268,7 @@ type AppDbContext (opts : DbContextOptions<AppDbContext>) =
.Include(fun r -> r.history)
.Include(fun r -> r.notes)
.FirstOrDefaultAsync(fun r -> r.requestId = requestId && r.userId = userId)
match toOption fullReq with
match Option.fromObject fullReq with
| Some _ -> return Some { req with history = List.ofSeq fullReq.history; notes = List.ofSeq fullReq.notes }
| None -> return None
| None -> return None

View File

@ -15,13 +15,15 @@
<PackageReference Include="Giraffe" Version="3.6.0" />
<PackageReference Include="Giraffe.TokenRouter" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.FSharpLu" Version="0.10.29" />
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.10.29" />
<PackageReference Include="NCuid.NetCore" Version="1.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.0" />
<PackageReference Include="TaskBuilder.fs" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.5.2" />
<PackageReference Update="FSharp.Core" Version="4.6.2" />
</ItemGroup>
<ItemGroup>

View File

@ -4,11 +4,11 @@ open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open System
/// Configuration functions for the application
module Configure =
open Giraffe
open Giraffe.Serialization
open Giraffe.TokenRouter
open Microsoft.AspNetCore.Authentication.JwtBearer
open Microsoft.AspNetCore.Server.Kestrel.Core
@ -16,7 +16,9 @@ module Configure =
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Logging
open Microsoft.FSharpLu.Json
open MyPrayerJournal
open Newtonsoft.Json
/// Set up the configuration for the app
let configuration (ctx : WebHostBuilderContext) (cfg : IConfigurationBuilder) =
@ -30,6 +32,15 @@ module Configure =
let kestrel (ctx : WebHostBuilderContext) (opts : KestrelServerOptions) =
(ctx.Configuration.GetSection >> opts.Configure >> ignore) "Kestrel"
/// Custom settings for the JSON serializer (uses compact representation for options and DUs)
let jsonSettings =
let x = NewtonsoftJsonSerializer.DefaultSettings
x.Converters.Add (CompactUnionJsonConverter (true))
x.NullValueHandling <- NullValueHandling.Ignore
x.MissingMemberHandling <- MissingMemberHandling.Error
x.Formatting <- Formatting.Indented
x
/// Configure dependency injection
let services (sc : IServiceCollection) =
use sp = sc.BuildServiceProvider()
@ -48,6 +59,7 @@ module Configure =
opts.Audience <- jwtCfg.["Id"])
|> ignore
sc.AddDbContext<AppDbContext>(fun opts -> opts.UseNpgsql(cfg.GetConnectionString "mpj") |> ignore)
.AddSingleton<IJsonSerializer>(NewtonsoftJsonSerializer jsonSettings)
|> ignore
/// Routes for the available URLs within myPrayerJournal

View File

@ -1,6 +1,6 @@
{
"name": "my-prayer-journal",
"version": "1.0.2",
"version": "1.1.0",
"description": "myPrayerJournal - Front End",
"author": "Daniel J. Summers <daniel@bitbadger.solutions>",
"private": true,

View File

@ -15,7 +15,7 @@ article.mpj-main-content(role='main')
tbody
tr(v-for='item in log' :key='item.asOf')
td {{ item.status }} on #[span.mpj-text-nowrap {{ formatDate(item.asOf) }}]
td(v-if='item.text').mpj-request-text {{ item.text.fields[0] }}
td(v-if='item.text').mpj-request-text {{ item.text }}
td(v-else) &nbsp;
p(v-else) Loading request...
</template>
@ -52,11 +52,11 @@ export default {
lastText () {
return this.request.history
.filter(hist => hist.text)
.sort(asOfDesc)[0].text.fields[0]
.sort(asOfDesc)[0].text
},
log () {
const allHistory = (this.request.notes || [])
.map(note => ({ asOf: note.asOf, text: { case: 'Some', fields: [ note.notes ] }, status: 'Notes' }))
.map(note => ({ asOf: note.asOf, text: note.notes, status: 'Notes' }))
.concat(this.request.history)
.sort(asOfDesc)
// Skip the first entry for answered requests; that info is already displayed