A lot is working...

...but a lot is not. The JSON for the journal is not including the Id field; I suspect the majority of the problems reside with that issue.
This commit is contained in:
Daniel J. Summers
2019-07-30 23:56:34 -05:00
parent 87ce966ca1
commit c587d9772f
15 changed files with 179 additions and 310 deletions

View File

@@ -63,6 +63,7 @@ module Indexes =
userId = req.userId,
text = req.history.Where(hist => hist.text != null).OrderByDescending(hist => hist.asOf).First().text,
asOf = req.history.OrderByDescending(hist => hist.asOf).First().asOf,
lastStatus = req.history.OrderByDescending(hist => hist.asOf).First().status,
snoozedUntil = req.snoozedUntil,
showAfter = req.showAfter,
recurType = req.recurType,
@@ -70,8 +71,9 @@ module Indexes =
})"
]
this.Fields <-
[ "text", IndexFieldOptions (Storage = Nullable FieldStorage.Yes)
"asOf", IndexFieldOptions (Storage = Nullable FieldStorage.Yes)
[ "text", IndexFieldOptions (Storage = Nullable FieldStorage.Yes)
"asOf", IndexFieldOptions (Storage = Nullable FieldStorage.Yes)
"lastStatus", IndexFieldOptions (Storage = Nullable FieldStorage.Yes)
]
|> dict
|> Dictionary<string, IndexFieldOptions>
@@ -105,244 +107,103 @@ module Extensions =
r.Values.["Item"] <- item
PatchCommandData (docId, null, r, null)
// Extensions for the RavenDB session type
type IAsyncDocumentSession with
/// Add a history entry
member this.AddHistory (reqId : RequestId) (hist : History) =
listPush "history" (RequestId.toString reqId) hist
|> this.Advanced.Defer
/// Add a note
member this.AddNote (reqId : RequestId) (note : Note) =
listPush "notes" (RequestId.toString reqId) note
|> this.Advanced.Defer
/// Add a request
member this.AddRequest req =
this.StoreAsync (req, req.Id)
/// Retrieve all answered requests for the given user
// TODO: not right
member this.AnsweredRequests (userId : UserId) =
sprintf "%s where userId = '%s' and lastStatus = 'Answered' order by asOf as long desc"
(fromIndex typeof<Requests_AsJournal>) (UserId.toString userId)
|> this.Advanced.AsyncRawQuery<JournalRequest>
/// Retrieve the user's current journal
// TODO: probably not right either
member this.JournalByUserId (userId : UserId) =
sprintf "%s where userId = '%s' and lastStatus <> 'Answered' order by showAfter as long"
(fromIndex typeof<Requests_AsJournal>) (UserId.toString userId)
|> this.Advanced.AsyncRawQuery<JournalRequest>
/// Retrieve a request, including its history and notes, by its ID and user ID
member this.TryFullRequestById (reqId : RequestId) userId =
task {
let! req = RequestId.toString reqId |> this.LoadAsync
match Option.fromObject req with
| Some r when r.userId = userId -> return Some r
| _ -> return None
}
/// Retrieve a request by its ID and user ID (without notes and history)
member this.TryRequestById reqId userId =
task {
match! this.TryFullRequestById reqId userId with
| Some r -> return Some { r with history = []; notes = [] }
| _ -> return None
}
/// Retrieve notes for a request by its ID and user ID
member this.NotesById reqId userId =
task {
match! this.TryRequestById reqId userId with
| Some req -> return req.notes
| None -> return []
}
/// Retrieve a journal request by its ID and user ID
member this.TryJournalById (reqId : RequestId) userId =
task {
let! req =
this.Query<Request, Requests_AsJournal>()
.Where(fun x -> x.Id = (RequestId.toString reqId) && x.userId = userId)
.ProjectInto<JournalRequest>()
.FirstOrDefaultAsync ()
return Option.fromObject req
}
/// Update the recurrence for a request
member this.UpdateRecurrence (reqId : RequestId) (recurType : Recurrence) (recurCount : int16) =
let r = PatchRequest()
r.Script <- "this.recurType = args.Type; this.recurCount = args.Count"
r.Values.["Type"] <- string recurType
r.Values.["Count"] <- recurCount
PatchCommandData (RequestId.toString reqId, null, r, null) |> this.Advanced.Defer
/// Update the "show after" timestamp for a request
member this.UpdateShowAfter (reqId : RequestId) (showAfter : Ticks) =
fieldUpdate "showAfter" (RequestId.toString reqId) (Ticks.toLong showAfter)
|> this.Advanced.Defer
/// Update a snoozed request
member this.UpdateSnoozed (reqId : RequestId) (until : Ticks) =
let r = PatchRequest()
r.Script <- "this.snoozedUntil = args.Item; this.showAfter = args.Item"
r.Values.["Item"] <- Ticks.toLong until
PatchCommandData (RequestId.toString reqId, null, r, null) |> this.Advanced.Defer
(*
/// Entity Framework configuration for myPrayerJournal
module internal EFConfig =
/// All data manipulations within myPrayerJournal
module Data =
open FSharp.EFCore.OptionConverter
open System.Collections.Generic
open Indexes
open Raven.Client.Documents.Session
/// Configure EF properties for all entity types
let configure (mb : ModelBuilder) =
mb.Entity<History> (
fun m ->
m.ToTable "history" |> ignore
m.HasKey ("requestId", "asOf") |> ignore
m.Property(fun e -> e.requestId).IsRequired () |> ignore
m.Property(fun e -> e.asOf).IsRequired () |> ignore
m.Property(fun e -> e.status).IsRequired() |> ignore
m.Property(fun e -> e.text) |> ignore)
|> ignore
mb.Model.FindEntityType(typeof<History>).FindProperty("text").SetValueConverter (OptionConverter<string> ())
mb.Entity<Note> (
fun m ->
m.ToTable "note" |> ignore
m.HasKey ("requestId", "asOf") |> ignore
m.Property(fun e -> e.requestId).IsRequired () |> ignore
m.Property(fun e -> e.asOf).IsRequired () |> ignore
m.Property(fun e -> e.notes).IsRequired () |> ignore)
|> ignore
mb.Entity<Request> (
fun m ->
m.ToTable "request" |> ignore
m.HasKey(fun e -> e.requestId :> obj) |> ignore
m.Property(fun e -> e.requestId).IsRequired () |> ignore
m.Property(fun e -> e.enteredOn).IsRequired () |> ignore
m.Property(fun e -> e.userId).IsRequired () |> ignore
m.Property(fun e -> e.snoozedUntil).IsRequired () |> ignore
m.Property(fun e -> e.showAfter).IsRequired () |> ignore
m.Property(fun e -> e.recurType).IsRequired() |> ignore
m.Property(fun e -> e.recurCount).IsRequired() |> ignore
m.HasMany(fun e -> e.history :> IEnumerable<History>)
.WithOne()
.HasForeignKey(fun e -> e.requestId :> obj)
|> ignore
m.HasMany(fun e -> e.notes :> IEnumerable<Note>)
.WithOne()
.HasForeignKey(fun e -> e.requestId :> obj)
|> ignore)
|> ignore
mb.Query<JournalRequest> (
fun m ->
m.ToView "journal" |> ignore
m.Ignore(fun e -> e.history :> obj) |> ignore
m.Ignore(fun e -> e.notes :> obj) |> ignore)
|> ignore
open System.Linq
/// Data context
type AppDbContext (opts : DbContextOptions<AppDbContext>) =
inherit DbContext (opts)
[<DefaultValue>]
val mutable private history : DbSet<History>
[<DefaultValue>]
val mutable private notes : DbSet<Note>
[<DefaultValue>]
val mutable private requests : DbSet<Request>
[<DefaultValue>]
val mutable private journal : DbQuery<JournalRequest>
member this.History
with get () = this.history
and set v = this.history <- v
member this.Notes
with get () = this.notes
and set v = this.notes <- v
member this.Requests
with get () = this.requests
and set v = this.requests <- v
member this.Journal
with get () = this.journal
and set v = this.journal <- v
/// Add a history entry
let addHistory reqId (hist : History) (sess : IAsyncDocumentSession) =
sess.Advanced.Patch<Request, History> (
RequestId.toString reqId,
(fun r -> r.history :> IEnumerable<History>),
fun (h : JavaScriptArray<History>) -> h.Add (hist) :> obj)
override __.OnModelCreating (mb : ModelBuilder) =
base.OnModelCreating mb
EFConfig.configure mb
/// Register a disconnected entity with the context, having the given state
member private this.RegisterAs<'TEntity when 'TEntity : not struct> state e =
this.Entry<'TEntity>(e).State <- state
/// Add a note
let addNote reqId (note : Note) (sess : IAsyncDocumentSession) =
sess.Advanced.Patch<Request, Note> (
RequestId.toString reqId,
(fun r -> r.notes :> IEnumerable<Note>),
fun (h : JavaScriptArray<Note>) -> h.Add (note) :> obj)
/// Add an entity instance to the context
member this.AddEntry e =
this.RegisterAs EntityState.Added e
/// Update the entity instance's values
member this.UpdateEntry e =
this.RegisterAs EntityState.Modified e
/// Add a request
let addRequest req (sess : IAsyncDocumentSession) =
sess.StoreAsync (req, req.Id)
/// Retrieve all answered requests for the given user
member this.AnsweredRequests userId : JournalRequest seq =
upcast this.Journal
let answeredRequests userId (sess : IAsyncDocumentSession) =
sess.Query<JournalRequest, Requests_AsJournal>()
.Where(fun r -> r.userId = userId && r.lastStatus = "Answered")
.OrderByDescending(fun r -> r.asOf)
.ProjectInto<JournalRequest>()
.ToListAsync()
/// Retrieve the user's current journal
member this.JournalByUserId userId : JournalRequest seq =
upcast this.Journal
.Where(fun r -> r.userId = userId && r.lastStatus <> "Answered")
.OrderBy(fun r -> r.showAfter)
/// Retrieve a request by its ID and user ID
member this.TryRequestById reqId userId =
let journalByUserId userId (sess : IAsyncDocumentSession) =
task {
let! req = this.Requests.AsNoTracking().FirstOrDefaultAsync(fun r -> r.requestId = reqId && r.userId = userId)
return Option.fromObject req
let! jrnl =
sess.Query<JournalRequest, Requests_AsJournal>()
.Where(fun r -> r.userId = userId && r.lastStatus <> "Answered")
.OrderBy(fun r -> r.asOf)
.ProjectInto<JournalRequest>()
.ToListAsync()
return
jrnl
|> List.ofSeq
|> List.map (fun r -> r.history <- []; r.notes <- []; r)
}
/// Retrieve notes for a request by its ID and user ID
member this.NotesById reqId userId =
/// Save changes in the current document session
let saveChanges (sess : IAsyncDocumentSession) =
sess.SaveChangesAsync ()
/// Retrieve a request, including its history and notes, by its ID and user ID
let tryFullRequestById reqId userId (sess : IAsyncDocumentSession) =
task {
match! this.TryRequestById reqId userId with
| Some _ -> return this.Notes.AsNoTracking().Where(fun n -> n.requestId = reqId) |> List.ofSeq
let! req = RequestId.toString reqId |> sess.LoadAsync
return match Option.fromObject req with Some r when r.userId = userId -> Some r | _ -> None
}
/// Retrieve a request by its ID and user ID (without notes and history)
let tryRequestById reqId userId (sess : IAsyncDocumentSession) =
task {
match! tryFullRequestById reqId userId sess with
| Some r -> return Some { r with history = []; notes = [] }
| _ -> return None
}
/// Retrieve notes for a request by its ID and user ID
let notesById reqId userId (sess : IAsyncDocumentSession) =
task {
match! tryFullRequestById reqId userId sess with
| Some req -> return req.notes
| None -> return []
}
/// Retrieve a journal request by its ID and user ID
member this.TryJournalById reqId userId =
let tryJournalById reqId userId (sess : IAsyncDocumentSession) =
task {
let! req = this.Journal.FirstOrDefaultAsync(fun r -> r.requestId = reqId && r.userId = userId)
let! req =
sess.Query<Request, Requests_AsJournal>()
.Where(fun x -> x.Id = (RequestId.toString reqId) && x.userId = userId)
.ProjectInto<JournalRequest>()
.FirstOrDefaultAsync ()
return Option.fromObject req
}
/// Retrieve a request, including its history and notes, by its ID and user ID
member this.TryFullRequestById requestId userId =
task {
match! this.TryJournalById requestId userId with
| Some req ->
let! fullReq =
this.Requests.AsNoTracking()
.Include(fun r -> r.history)
.Include(fun r -> r.notes)
.FirstOrDefaultAsync(fun r -> r.requestId = requestId && r.userId = userId)
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
}
*)
/// Update the recurrence for a request
let updateRecurrence reqId recurType recurCount (sess : IAsyncDocumentSession) =
sess.Advanced.Patch<Request, Recurrence> (RequestId.toString reqId, (fun r -> r.recurType), recurType)
sess.Advanced.Patch<Request, int16> (RequestId.toString reqId, (fun r -> r.recurCount), recurCount)
/// Update a snoozed request
let updateSnoozed reqId until (sess : IAsyncDocumentSession) =
sess.Advanced.Patch<Request, Ticks> (RequestId.toString reqId, (fun r -> r.snoozedUntil), until)
sess.Advanced.Patch<Request, Ticks> (RequestId.toString reqId, (fun r -> r.showAfter), until)
/// Update the "show after" timestamp for a request
let updateShowAfter reqId showAfter (sess : IAsyncDocumentSession) =
sess.Advanced.Patch<Request, Ticks> (RequestId.toString reqId, (fun r -> r.showAfter), showAfter)