First cut of migration program
This commit is contained in:
parent
42e3a58131
commit
194cd2b5cc
@ -5,6 +5,31 @@ open Npgsql
|
||||
open Npgsql.FSharp
|
||||
open PrayerTracker.Entities
|
||||
|
||||
/// Table names
|
||||
[<RequireQualifiedAccess>]
|
||||
module Table =
|
||||
|
||||
/// The church table
|
||||
[<Literal>]
|
||||
let Church = "church"
|
||||
|
||||
/// The small group table
|
||||
[<Literal>]
|
||||
let Group = "small_group"
|
||||
|
||||
/// The small group member table
|
||||
[<Literal>]
|
||||
let Member = "member"
|
||||
|
||||
/// The prayer request table
|
||||
[<Literal>]
|
||||
let Request = "prayer_request"
|
||||
|
||||
/// The user table
|
||||
[<Literal>]
|
||||
let User = "pt_user"
|
||||
|
||||
|
||||
/// Helper functions for the PostgreSQL data implementation
|
||||
[<AutoOpen>]
|
||||
module private Helpers =
|
||||
@ -100,6 +125,7 @@ module private Helpers =
|
||||
IsAdmin = row.bool "is_admin"
|
||||
PasswordHash = row.string "password_hash"
|
||||
LastSeen = row.fieldValueOrNone<Instant> "last_seen"
|
||||
SmallGroups = []
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,6 +127,15 @@ type RequestSort =
|
||||
| _ -> invalidArg "code" $"Unknown code {code}"
|
||||
|
||||
|
||||
/// Type for a time zone ID
|
||||
type TimeZoneId =
|
||||
| TimeZoneId of string
|
||||
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| TimeZoneId it -> it
|
||||
|
||||
|
||||
open System
|
||||
|
||||
/// PK type for the Church entity
|
||||
@ -173,15 +182,6 @@ type SmallGroupId =
|
||||
| SmallGroupId guid -> guid
|
||||
|
||||
|
||||
/// PK type for the TimeZone entity
|
||||
type TimeZoneId =
|
||||
| TimeZoneId of string
|
||||
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| TimeZoneId it -> it
|
||||
|
||||
|
||||
/// PK type for the User entity
|
||||
type UserId =
|
||||
| UserId of Guid
|
||||
@ -523,6 +523,9 @@ type User =
|
||||
|
||||
/// The last time the user was seen (set whenever the user is loaded into a session)
|
||||
LastSeen: Instant option
|
||||
|
||||
/// The small groups to which this user is authorized
|
||||
SmallGroups: SmallGroupId list
|
||||
}
|
||||
|
||||
/// The full name of the user
|
||||
@ -536,7 +539,8 @@ type User =
|
||||
Email = ""
|
||||
IsAdmin = false
|
||||
PasswordHash = ""
|
||||
LastSeen = None }
|
||||
LastSeen = None
|
||||
SmallGroups = [] }
|
||||
|
||||
|
||||
/// Cross-reference between user and small group
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BitBadger.Documents.Postgres" Version="3.1.0" />
|
||||
<PackageReference Include="BitBadger.Documents.Sqlite" Version="4.0.1" />
|
||||
<PackageReference Include="Giraffe" Version="7.0.2" />
|
||||
<PackageReference Include="NodaTime" Version="3.2.0" />
|
||||
<PackageReference Include="Npgsql.FSharp" Version="5.7.0" />
|
||||
|
20
src/PrayerTracker.MigrateV9/PrayerTracker.MigrateV9.fsproj
Normal file
20
src/PrayerTracker.MigrateV9/PrayerTracker.MigrateV9.fsproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PrayerTracker.Data\PrayerTracker.Data.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BitBadger.Documents.Postgres" Version="4.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
141
src/PrayerTracker.MigrateV9/Program.fs
Normal file
141
src/PrayerTracker.MigrateV9/Program.fs
Normal file
@ -0,0 +1,141 @@
|
||||
|
||||
open NodaTime
|
||||
open Npgsql.FSharp
|
||||
open PrayerTracker.Data
|
||||
open PrayerTracker.Entities
|
||||
|
||||
module PgMappings =
|
||||
/// Map a row to a Church instance
|
||||
let mapToChurch (row : RowReader) =
|
||||
{ Id = ChurchId (row.uuid "id")
|
||||
Name = row.string "church_name"
|
||||
City = row.string "city"
|
||||
State = row.string "state"
|
||||
HasVpsInterface = row.bool "has_vps_interface"
|
||||
InterfaceAddress = row.stringOrNone "interface_address"
|
||||
}
|
||||
|
||||
/// Map a row to a ListPreferences instance
|
||||
let mapToListPreferences (row : RowReader) =
|
||||
{ SmallGroupId = SmallGroupId (row.uuid "small_group_id")
|
||||
DaysToKeepNew = row.int "days_to_keep_new"
|
||||
DaysToExpire = row.int "days_to_expire"
|
||||
LongTermUpdateWeeks = row.int "long_term_update_weeks"
|
||||
EmailFromName = row.string "email_from_name"
|
||||
EmailFromAddress = row.string "email_from_address"
|
||||
Fonts = row.string "fonts"
|
||||
HeadingColor = row.string "heading_color"
|
||||
LineColor = row.string "line_color"
|
||||
HeadingFontSize = row.int "heading_font_size"
|
||||
TextFontSize = row.int "text_font_size"
|
||||
GroupPassword = row.string "group_password"
|
||||
IsPublic = row.bool "is_public"
|
||||
PageSize = row.int "page_size"
|
||||
TimeZoneId = TimeZoneId (row.string "time_zone_id")
|
||||
RequestSort = RequestSort.Parse (row.string "request_sort")
|
||||
DefaultEmailType = EmailFormat.Parse (row.string "default_email_type")
|
||||
AsOfDateDisplay = AsOfDateDisplay.Parse (row.string "as_of_date_display")
|
||||
}
|
||||
|
||||
/// Map a row to a Member instance
|
||||
let mapToMember (row : RowReader) =
|
||||
{ Id = MemberId (row.uuid "id")
|
||||
SmallGroupId = SmallGroupId (row.uuid "small_group_id")
|
||||
Name = row.string "member_name"
|
||||
Email = row.string "email"
|
||||
Format = row.stringOrNone "email_format" |> Option.map EmailFormat.Parse
|
||||
}
|
||||
|
||||
/// Map a row to a Prayer Request instance
|
||||
let mapToPrayerRequest (row : RowReader) =
|
||||
{ Id = PrayerRequestId (row.uuid "id")
|
||||
UserId = UserId (row.uuid "user_id")
|
||||
SmallGroupId = SmallGroupId (row.uuid "small_group_id")
|
||||
EnteredDate = row.fieldValue<Instant> "entered_date"
|
||||
UpdatedDate = row.fieldValue<Instant> "updated_date"
|
||||
Requestor = row.stringOrNone "requestor"
|
||||
Text = row.string "request_text"
|
||||
NotifyChaplain = row.bool "notify_chaplain"
|
||||
RequestType = PrayerRequestType.Parse (row.string "request_type")
|
||||
Expiration = Expiration.Parse (row.string "expiration")
|
||||
}
|
||||
|
||||
/// Map a row to a Small Group instance
|
||||
let mapToSmallGroup (row : RowReader) =
|
||||
{ Id = SmallGroupId (row.uuid "id")
|
||||
ChurchId = ChurchId (row.uuid "church_id")
|
||||
Name = row.string "group_name"
|
||||
Preferences = ListPreferences.Empty
|
||||
}
|
||||
|
||||
/// Map a row to a Small Group instance with populated list preferences
|
||||
let mapToSmallGroupWithPreferences (row : RowReader) =
|
||||
{ mapToSmallGroup row with
|
||||
Preferences = mapToListPreferences row
|
||||
}
|
||||
|
||||
/// Map a row to a User instance
|
||||
let mapToUser (row : RowReader) =
|
||||
{ Id = UserId (row.uuid "id")
|
||||
FirstName = row.string "first_name"
|
||||
LastName = row.string "last_name"
|
||||
Email = row.string "email"
|
||||
IsAdmin = row.bool "is_admin"
|
||||
PasswordHash = row.string "password_hash"
|
||||
LastSeen = row.fieldValueOrNone<Instant> "last_seen"
|
||||
SmallGroups = []
|
||||
}
|
||||
|
||||
// TODO: Configure PostgreSQL and SQLite connections
|
||||
|
||||
task {
|
||||
|
||||
let source = BitBadger.Documents.Postgres.Configuration.dataSource ()
|
||||
|
||||
let! churches =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT * FROM pt.church"
|
||||
|> Sql.executeAsync PgMappings.mapToChurch
|
||||
for church in churches do
|
||||
do! BitBadger.Documents.Sqlite.Document.insert Table.Church church
|
||||
printfn "Migrated %d churches" churches.Length
|
||||
|
||||
let! groups =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT sg.*, lp.* FROM pt.small_group sg
|
||||
INNER JOIN pt.list_preference lp ON lp.small_group_id = sg.id"
|
||||
|> Sql.executeAsync PgMappings.mapToSmallGroupWithPreferences
|
||||
for group in groups do
|
||||
do! BitBadger.Documents.Sqlite.Document.insert Table.Group group
|
||||
printfn "Migrated %d groups" groups.Length
|
||||
|
||||
let! members =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT * from pt.member"
|
||||
|> Sql.executeAsync PgMappings.mapToMember
|
||||
for mbr in members do
|
||||
do! BitBadger.Documents.Sqlite.Document.insert Table.Member mbr
|
||||
printfn "Migrated %d members" members.Length
|
||||
|
||||
let! requests =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT * from pt.prayer_request"
|
||||
|> Sql.executeAsync PgMappings.mapToPrayerRequest
|
||||
for request in requests do
|
||||
do! BitBadger.Documents.Sqlite.Document.insert Table.Request request
|
||||
printfn "Migrated %d requests" requests.Length
|
||||
|
||||
let! users =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT * FROM pt.pt_user"
|
||||
|> Sql.executeAsync PgMappings.mapToUser
|
||||
for user in users do
|
||||
let! groups =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query "SELECT small_group_id FROM pt.user_small_group WHERE user_id = :user_id"
|
||||
|> Sql.parameters [ ":user_id", Sql.uuid user.Id.Value ]
|
||||
|> Sql.executeAsync (fun row -> (row.uuid >> SmallGroupId) "small_group_id")
|
||||
do! BitBadger.Documents.Sqlite.Document.insert Table.User { user with SmallGroups = groups }
|
||||
printfn "Migrated %d users" users.Length
|
||||
|
||||
} |> Async.AwaitTask |> Async.RunSynchronously
|
@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
Directory.Build.props = Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PrayerTracker.MigrateV9", "PrayerTracker.MigrateV9\PrayerTracker.MigrateV9.fsproj", "{CE7C5972-AC9A-44A8-8265-771483FD87DB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -38,6 +40,10 @@ Global
|
||||
{2B5BA107-9BDA-4A1D-A9AF-AFEE6BF12270}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2B5BA107-9BDA-4A1D-A9AF-AFEE6BF12270}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2B5BA107-9BDA-4A1D-A9AF-AFEE6BF12270}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CE7C5972-AC9A-44A8-8265-771483FD87DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CE7C5972-AC9A-44A8-8265-771483FD87DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CE7C5972-AC9A-44A8-8265-771483FD87DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CE7C5972-AC9A-44A8-8265-771483FD87DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
Loading…
x
Reference in New Issue
Block a user