Add migration program; Add RequestAction DU

This commit is contained in:
Daniel J. Summers 2019-07-28 20:47:11 -05:00
parent 221d95a2e2
commit a2ef84bc1e
4 changed files with 139 additions and 6 deletions

View File

@ -44,6 +44,7 @@ type Recurrence =
| Weeks | Weeks
module Recurrence = module Recurrence =
/// The string reprsentation used in the database and the web app /// The string reprsentation used in the database and the web app
// TODO/FIXME: will this be true in v2? it's not in the database...
let toString x = let toString x =
match x with match x with
| Immediate -> "immediate" | Immediate -> "immediate"
@ -67,13 +68,30 @@ module Recurrence =
| Weeks -> 604800000L | Weeks -> 604800000L
/// The action taken on a request as part of a history entry
type RequestAction =
| Created
| Prayed
| Updated
| Answered
module RequestAction =
/// Create a RequestAction from a string
let fromString x =
match x with
| "Created" -> Created
| "Prayed" -> Prayed
| "Updated" -> Updated
| "Answered" -> Answered
| _ -> (sprintf "Bad request action %s" >> invalidOp) x
/// History is a record of action taken on a prayer request, including updates to its text /// History is a record of action taken on a prayer request, including updates to its text
[<CLIMutable; NoComparison; NoEquality>] [<CLIMutable; NoComparison; NoEquality>]
type History = type History =
{ /// The time when this history entry was made { /// The time when this history entry was made
asOf : Ticks asOf : Ticks
/// The status for this history entry /// The status for this history entry
status : string status : RequestAction
/// The text of the update, if applicable /// The text of the update, if applicable
text : string option text : string option
} }
@ -81,7 +99,7 @@ with
/// An empty history entry /// An empty history entry
static member empty = static member empty =
{ asOf = Ticks 0L { asOf = Ticks 0L
status = "" status = Created
text = None text = None
} }

View File

@ -175,7 +175,7 @@ module Request =
history = [ history = [
{ History.empty with { History.empty with
asOf = now asOf = now
status = "Created" status = Created
text = Some r.requestText text = Some r.requestText
} }
] ]
@ -197,14 +197,15 @@ module Request =
| Some req -> | Some req ->
let! hist = ctx.BindJsonAsync<Models.HistoryEntry> () let! hist = ctx.BindJsonAsync<Models.HistoryEntry> ()
let now = jsNow () let now = jsNow ()
let act = RequestAction.fromString hist.status
{ History.empty with { History.empty with
asOf = now asOf = now
status = hist.status status = act
text = match hist.updateText with null | "" -> None | x -> Some x text = match hist.updateText with null | "" -> None | x -> Some x
} }
|> sess.AddHistory reqId |> sess.AddHistory reqId
match hist.status with match act with
| "Prayed" -> | Prayed ->
(Ticks.toLong now) + (Recurrence.duration req.recurType * int64 req.recurCount) (Ticks.toLong now) + (Recurrence.duration req.recurType * int64 req.recurCount)
|> (Ticks >> sess.UpdateShowAfter reqId) |> (Ticks >> sess.UpdateShowAfter reqId)
| _ -> () | _ -> ()

94
src/migrate/Program.fs Normal file
View File

@ -0,0 +1,94 @@

open Microsoft.FSharpLu.Json
open MyPrayerJournal
open Npgsql
open Raven.Client.Documents
type NpgsqlDataReader with
member this.getShort = this.GetOrdinal >> this.GetInt16
member this.getString = this.GetOrdinal >> this.GetString
member this.getTicks = this.GetOrdinal >> this.GetInt64 >> Ticks
member this.isNull = this.GetOrdinal >> this.IsDBNull
let pgConn () =
let c = new NpgsqlConnection "Host=severus-server;Database=mpj;Username=mpj;Password=devpassword;Application Name=myPrayerJournal"
c.Open ()
c
let isValidStatus stat =
try
(RequestAction.fromString >> ignore) stat
true
with _ -> false
let getHistory reqId =
use conn = pgConn ()
use cmd = conn.CreateCommand ()
cmd.CommandText <- """SELECT "asOf", status, text FROM mpj.history WHERE "requestId" = @reqId ORDER BY "asOf" """
(cmd.Parameters.Add >> ignore) (NpgsqlParameter ("@reqId", reqId :> obj))
use rdr = cmd.ExecuteReader ()
seq {
while rdr.Read () do
match (rdr.getString >> isValidStatus) "status" with
| true ->
yield
{ asOf = rdr.getTicks "asOf"
status = (rdr.getString >> RequestAction.fromString) "status"
text = match rdr.isNull "text" with true -> None | false -> (rdr.getString >> Some) "text"
}
| false ->
printf "Invalid status %s; skipped history entry %s/%i\n" (rdr.getString "status") reqId
((rdr.getTicks >> Ticks.toLong) "asOf")
}
|> List.ofSeq
let getNotes reqId =
use conn = pgConn ()
use cmd = conn.CreateCommand ()
cmd.CommandText <- """SELECT "asOf", notes FROM mpj.note WHERE "requestId" = @reqId"""
(cmd.Parameters.Add >> ignore) (NpgsqlParameter ("@reqId", reqId :> obj))
use rdr = cmd.ExecuteReader ()
seq {
while rdr.Read () do
yield
{ asOf = rdr.getTicks "asOf"
notes = rdr.getString "notes"
}
}
|> List.ofSeq
let migrateRequests (store : IDocumentStore) =
use sess = store.OpenSession ()
use conn = pgConn ()
use cmd = conn.CreateCommand ()
cmd.CommandText <-
"""SELECT "requestId", "enteredOn", "userId", "snoozedUntil", "showAfter", "recurType", "recurCount" FROM mpj.request"""
use rdr = cmd.ExecuteReader ()
while rdr.Read () do
let reqId = rdr.getString "requestId"
sess.Store (
{ Id = (RequestId.fromIdString >> RequestId.toString) reqId
enteredOn = rdr.getTicks "enteredOn"
userId = (rdr.getString >> UserId) "userId"
snoozedUntil = rdr.getTicks "snoozedUntil"
showAfter = rdr.getTicks "showAfter"
recurType = (rdr.getString >> Recurrence.fromString) "recurType"
recurCount = rdr.getShort "recurCount"
history = getHistory reqId
notes = getNotes reqId
})
sess.SaveChanges ()
[<EntryPoint>]
let main argv =
let raven = new DocumentStore (Urls = [| "http://localhost:8080" |], Database = "myPrayerJournal")
raven.Conventions.CustomizeJsonSerializer <-
fun x ->
x.Converters.Add (RequestIdJsonConverter ())
x.Converters.Add (TicksJsonConverter ())
x.Converters.Add (UserIdJsonConverter ())
x.Converters.Add (CompactUnionJsonConverter ())
let store = raven.Initialize ()
migrateRequests store
printfn "fin"
0 // return an integer exit code

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FSharp.Core" Version="4.6.2" />
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.2" />
<PackageReference Include="Npgsql" Version="4.0.8" />
<PackageReference Include="RavenDb.Client" Version="4.2.2" />
<ProjectReference Include="../MyPrayerJournal.Api/MyPrayerJournal.Api.fsproj" />
</ItemGroup>
</Project>