Update deps; WIP on comments
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
/// Converters for discriminated union types
|
||||
/// <summary>Converters for discriminated union types</summary>
|
||||
module MyWebLog.Converters
|
||||
|
||||
open MyWebLog
|
||||
open System
|
||||
|
||||
/// JSON.NET converters for discriminated union types
|
||||
/// <summary>JSON.NET converters for discriminated union types</summary>
|
||||
module Json =
|
||||
|
||||
|
||||
open Newtonsoft.Json
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="CategoryId" /> type</summary>
|
||||
type CategoryIdConverter() =
|
||||
inherit JsonConverter<CategoryId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: CategoryId, _: JsonSerializer) =
|
||||
@@ -16,6 +17,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: CategoryId, _: bool, _: JsonSerializer) =
|
||||
(string >> CategoryId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="CommentId" /> type</summary>
|
||||
type CommentIdConverter() =
|
||||
inherit JsonConverter<CommentId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: CommentId, _: JsonSerializer) =
|
||||
@@ -23,6 +25,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: CommentId, _: bool, _: JsonSerializer) =
|
||||
(string >> CommentId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="CommentStatus" /> type</summary>
|
||||
type CommentStatusConverter() =
|
||||
inherit JsonConverter<CommentStatus>()
|
||||
override _.WriteJson(writer: JsonWriter, value: CommentStatus, _: JsonSerializer) =
|
||||
@@ -30,6 +33,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: CommentStatus, _: bool, _: JsonSerializer) =
|
||||
(string >> CommentStatus.Parse) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="CustomFeedId" /> type</summary>
|
||||
type CustomFeedIdConverter() =
|
||||
inherit JsonConverter<CustomFeedId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: CustomFeedId, _: JsonSerializer) =
|
||||
@@ -37,27 +41,31 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: CustomFeedId, _: bool, _: JsonSerializer) =
|
||||
(string >> CustomFeedId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="CustomFeedSource" /> type</summary>
|
||||
type CustomFeedSourceConverter() =
|
||||
inherit JsonConverter<CustomFeedSource>()
|
||||
override _.WriteJson(writer: JsonWriter, value: CustomFeedSource, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: CustomFeedSource, _: bool, _: JsonSerializer) =
|
||||
(string >> CustomFeedSource.Parse) reader.Value
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="ExplicitRating" /> type</summary>
|
||||
type ExplicitRatingConverter() =
|
||||
inherit JsonConverter<ExplicitRating>()
|
||||
override _.WriteJson(writer: JsonWriter, value: ExplicitRating, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: ExplicitRating, _: bool, _: JsonSerializer) =
|
||||
(string >> ExplicitRating.Parse) reader.Value
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="MarkupText" /> type</summary>
|
||||
type MarkupTextConverter() =
|
||||
inherit JsonConverter<MarkupText>()
|
||||
override _.WriteJson(writer: JsonWriter, value: MarkupText, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: MarkupText, _: bool, _: JsonSerializer) =
|
||||
(string >> MarkupText.Parse) reader.Value
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="Permalink" /> type</summary>
|
||||
type PermalinkConverter() =
|
||||
inherit JsonConverter<Permalink>()
|
||||
override _.WriteJson(writer: JsonWriter, value: Permalink, _: JsonSerializer) =
|
||||
@@ -65,6 +73,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: Permalink, _: bool, _: JsonSerializer) =
|
||||
(string >> Permalink) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="PageId" /> type</summary>
|
||||
type PageIdConverter() =
|
||||
inherit JsonConverter<PageId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: PageId, _: JsonSerializer) =
|
||||
@@ -72,6 +81,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: PageId, _: bool, _: JsonSerializer) =
|
||||
(string >> PageId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="PodcastMedium" /> type</summary>
|
||||
type PodcastMediumConverter() =
|
||||
inherit JsonConverter<PodcastMedium>()
|
||||
override _.WriteJson(writer: JsonWriter, value: PodcastMedium, _: JsonSerializer) =
|
||||
@@ -79,6 +89,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: PodcastMedium, _: bool, _: JsonSerializer) =
|
||||
(string >> PodcastMedium.Parse) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="PostId" /> type</summary>
|
||||
type PostIdConverter() =
|
||||
inherit JsonConverter<PostId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: PostId, _: JsonSerializer) =
|
||||
@@ -86,6 +97,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: PostId, _: bool, _: JsonSerializer) =
|
||||
(string >> PostId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="TagMapId" /> type</summary>
|
||||
type TagMapIdConverter() =
|
||||
inherit JsonConverter<TagMapId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: TagMapId, _: JsonSerializer) =
|
||||
@@ -93,6 +105,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: TagMapId, _: bool, _: JsonSerializer) =
|
||||
(string >> TagMapId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="ThemeAssetId" /> type</summary>
|
||||
type ThemeAssetIdConverter() =
|
||||
inherit JsonConverter<ThemeAssetId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: ThemeAssetId, _: JsonSerializer) =
|
||||
@@ -100,20 +113,23 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: ThemeAssetId, _: bool, _: JsonSerializer) =
|
||||
(string >> ThemeAssetId.Parse) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="ThemeId" /> type</summary>
|
||||
type ThemeIdConverter() =
|
||||
inherit JsonConverter<ThemeId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: ThemeId, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: ThemeId, _: bool, _: JsonSerializer) =
|
||||
(string >> ThemeId) reader.Value
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="UploadId" /> type</summary>
|
||||
type UploadIdConverter() =
|
||||
inherit JsonConverter<UploadId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: UploadId, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: UploadId, _: bool, _: JsonSerializer) =
|
||||
(string >> UploadId) reader.Value
|
||||
|
||||
|
||||
/// <summary>Converter for the <see cref="WebLogId" /> type</summary>
|
||||
type WebLogIdConverter() =
|
||||
inherit JsonConverter<WebLogId>()
|
||||
override _.WriteJson(writer: JsonWriter, value: WebLogId, _: JsonSerializer) =
|
||||
@@ -121,6 +137,7 @@ module Json =
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: WebLogId, _: bool, _: JsonSerializer) =
|
||||
(string >> WebLogId) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="WebLogUserId" /> type</summary>
|
||||
type WebLogUserIdConverter() =
|
||||
inherit JsonConverter<WebLogUserId> ()
|
||||
override _.WriteJson(writer: JsonWriter, value: WebLogUserId, _: JsonSerializer) =
|
||||
@@ -131,9 +148,9 @@ module Json =
|
||||
open Microsoft.FSharpLu.Json
|
||||
open NodaTime
|
||||
open NodaTime.Serialization.JsonNet
|
||||
|
||||
/// Configure a serializer to use these converters
|
||||
let configure (ser : JsonSerializer) =
|
||||
|
||||
/// <summary>Configure a serializer to use these converters (and other settings)</summary>
|
||||
let configure (ser: JsonSerializer) =
|
||||
// Our converters
|
||||
[ CategoryIdConverter() :> JsonConverter
|
||||
CommentIdConverter()
|
||||
@@ -160,12 +177,14 @@ module Json =
|
||||
ser.NullValueHandling <- NullValueHandling.Ignore
|
||||
ser.MissingMemberHandling <- MissingMemberHandling.Ignore
|
||||
ser
|
||||
|
||||
|
||||
/// Serializer settings extracted from a JsonSerializer (a property sure would be nice...)
|
||||
let mutable private serializerSettings : JsonSerializerSettings option = None
|
||||
|
||||
/// Extract settings from the serializer to be used in JsonConvert calls
|
||||
let settings (ser : JsonSerializer) =
|
||||
|
||||
/// <summary>Extract settings from the serializer to be used in <c>JsonConvert</c> calls</summary>
|
||||
/// <param name="ser">The serializer from which settings will be extracted if required</param>
|
||||
/// <returns>The serializer settings to use for <c>JsonConvert</c> calls</returns>
|
||||
let settings (ser: JsonSerializer) =
|
||||
if Option.isNone serializerSettings then
|
||||
serializerSettings <- JsonSerializerSettings (
|
||||
ConstructorHandling = ser.ConstructorHandling,
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BitBadger.Documents.Postgres" Version="4.0.0" />
|
||||
<PackageReference Include="BitBadger.Documents.Sqlite" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="BitBadger.Documents.Postgres" Version="4.0.1" />
|
||||
<PackageReference Include="BitBadger.Documents.Sqlite" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
||||
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.1.0" />
|
||||
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.2.0" />
|
||||
<PackageReference Include="Npgsql.NodaTime" Version="9.0.2" />
|
||||
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
||||
<PackageReference Include="RethinkDb.Driver.FSharp" Version="0.9.0-beta-07" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.100" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.101" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+45
-14
@@ -1,11 +1,16 @@
|
||||
/// Utility functions for manipulating data
|
||||
/// <summary>Utility functions for manipulating data</summary>
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal MyWebLog.Data.Utils
|
||||
|
||||
open MyWebLog
|
||||
open MyWebLog.ViewModels
|
||||
|
||||
/// Create a category hierarchy from the given list of categories
|
||||
/// <summary>Create a category hierarchy from the given list of categories</summary>
|
||||
/// <param name="cats">The categories from which the list should be generated</param>
|
||||
/// <param name="parentId">The ID of the parent category for this list</param>
|
||||
/// <param name="slugBase">The base URL to use in slugs for categories at this level</param>
|
||||
/// <param name="parentNames">The names of parent categories for this level</param>
|
||||
/// <returns>An array of <c>DisplayCategory</c> instances sorted alphabetically by parent category</returns>
|
||||
let rec orderByHierarchy (cats: Category list) parentId slugBase parentNames = seq {
|
||||
for cat in cats |> List.filter (fun c -> c.ParentId = parentId) do
|
||||
let fullSlug = (match slugBase with Some it -> $"{it}/" | None -> "") + cat.Slug
|
||||
@@ -19,48 +24,75 @@ let rec orderByHierarchy (cats: Category list) parentId slugBase parentNames = s
|
||||
yield! orderByHierarchy cats (Some cat.Id) (Some fullSlug) ([ cat.Name ] |> List.append parentNames)
|
||||
}
|
||||
|
||||
/// Get lists of items removed from and added to the given lists
|
||||
/// <summary>Get lists of items removed from and added to the given lists</summary>
|
||||
/// <typeparam name="T">The type of items in the list</typeparam>
|
||||
/// <typeparam name="U">The return type of the comparision function</typeparam>
|
||||
/// <param name="oldItems">The prior list</param>
|
||||
/// <param name="newItems">The current list</param>
|
||||
/// <param name="f">The function to use when comparing items in the list</param>
|
||||
/// <returns>A tuple with <c>fst</c> being added items and <c>snd</c> being removed items</returns>
|
||||
let diffLists<'T, 'U when 'U: equality> oldItems newItems (f: 'T -> 'U) =
|
||||
let diff compList = fun item -> not (compList |> List.exists (fun other -> f item = f other))
|
||||
List.filter (diff newItems) oldItems, List.filter (diff oldItems) newItems
|
||||
|
||||
/// Find the revisions added and removed
|
||||
/// <summary>Find the revisions added and removed</summary>
|
||||
/// <param name="oldRevs">The previous revisions</param>
|
||||
/// <param name="newRevs">The current revisions</param>
|
||||
/// <returns>A tuple with <c>fst</c> being added revisions and <c>snd</c> being removed revisions</returns>
|
||||
let diffRevisions (oldRevs: Revision list) newRevs =
|
||||
diffLists oldRevs newRevs (fun rev -> $"{rev.AsOf.ToUnixTimeTicks()}|{rev.Text}")
|
||||
|
||||
open MyWebLog.Converters
|
||||
open Newtonsoft.Json
|
||||
|
||||
/// Serialize an object to JSON
|
||||
/// <summary>Serialize an object to JSON</summary>
|
||||
/// <typeparam name="T">The type of the item being serialized</typeparam>
|
||||
/// <param name="ser">The JSON serializer whose settings should be used</param>
|
||||
/// <param name="item">The item to be serialized</param>
|
||||
/// <returns>A string with the given object serialized to JSON</returns>
|
||||
let serialize<'T> ser (item: 'T) =
|
||||
JsonConvert.SerializeObject(item, Json.settings ser)
|
||||
|
||||
/// Deserialize a JSON string
|
||||
/// <summary>Deserialize a JSON string</summary>
|
||||
/// <typeparam name="T">The type of the item being deserialized</typeparam>
|
||||
/// <param name="ser">The JSON serializer whose settings should be used</param>
|
||||
/// <param name="value">The string with the JSON representation of the item</param>
|
||||
/// <returns>The item deserialized from JSON</returns>
|
||||
let deserialize<'T> (ser: JsonSerializer) value =
|
||||
JsonConvert.DeserializeObject<'T>(value, Json.settings ser)
|
||||
|
||||
|
||||
open BitBadger.Documents
|
||||
|
||||
/// Create a document serializer using the given JsonSerializer
|
||||
/// <summary>Create a document serializer using the given JsonSerializer</summary>
|
||||
/// <param name="ser">The JSON.NET serializer on which the document serializer should be based</param>
|
||||
/// <returns>A document serializer instance</returns>
|
||||
let createDocumentSerializer ser =
|
||||
{ new IDocumentSerializer with
|
||||
member _.Serialize<'T>(it: 'T) : string = serialize ser it
|
||||
member _.Deserialize<'T>(it: string) : 'T = deserialize ser it
|
||||
}
|
||||
|
||||
/// Data migration utilities
|
||||
/// <summary>Data migration utilities</summary>
|
||||
module Migration =
|
||||
|
||||
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
/// The current database version
|
||||
/// <summary>The current database version</summary>
|
||||
let currentDbVersion = "v2.2"
|
||||
|
||||
/// Log a migration step
|
||||
/// <summary>Log a migration step</summary>
|
||||
/// <param name="log">The logger to which the message should be logged</param>
|
||||
/// <param name="migration">The migration being run</param>
|
||||
/// <param name="message">The log message</param>
|
||||
let logStep<'T> (log: ILogger<'T>) migration message =
|
||||
log.LogInformation $"Migrating %s{migration}: %s{message}"
|
||||
|
||||
/// Notify the user that a backup/restore
|
||||
/// <summary>Notify the user that a backup/restore is required to migrate</summary>
|
||||
/// <param name="log">The logger to which the message should be logged</param>
|
||||
/// <param name="oldVersion">The old (current) version of the database</param>
|
||||
/// <param name="newVersion">The new (application) version required</param>
|
||||
/// <param name="webLogs">All web logs contained in the database</param>
|
||||
let backupAndRestoreRequired log oldVersion newVersion webLogs =
|
||||
logStep log $"%s{oldVersion} to %s{newVersion}" "Requires Using Action"
|
||||
|
||||
@@ -74,7 +106,6 @@ module Migration =
|
||||
yield! webLogs |> List.map (fun (url, slug) -> $"./myWebLog backup %s{url} {oldVersion}.%s{slug}.json") ]
|
||||
|> String.concat "\n"
|
||||
|> log.LogWarning
|
||||
|
||||
|
||||
log.LogCritical "myWebLog will now exit"
|
||||
exit 1 |> ignore
|
||||
|
||||
Reference in New Issue
Block a user