From e8d63793ba69e62425a2ea37d1eed10c8d1a3d70 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sun, 31 Dec 2023 08:36:03 -0500 Subject: [PATCH] Migrate Postgres data to new library --- src/MyWebLog.Data/MyWebLog.Data.fsproj | 2 +- src/MyWebLog.Data/Postgres/PostgresCache.fs | 10 +-- .../Postgres/PostgresCategoryData.fs | 31 ++++----- src/MyWebLog.Data/Postgres/PostgresHelpers.fs | 23 ++----- .../Postgres/PostgresPageData.fs | 11 +-- .../Postgres/PostgresPostData.fs | 20 +++--- .../Postgres/PostgresTagMapData.fs | 7 +- .../Postgres/PostgresThemeData.fs | 27 ++++---- .../Postgres/PostgresUploadData.fs | 7 +- .../Postgres/PostgresWebLogData.fs | 11 +-- .../Postgres/PostgresWebLogUserData.fs | 16 ++--- src/MyWebLog.Data/PostgresData.fs | 68 +++++++++---------- src/MyWebLog/Program.fs | 4 +- 13 files changed, 111 insertions(+), 126 deletions(-) diff --git a/src/MyWebLog.Data/MyWebLog.Data.fsproj b/src/MyWebLog.Data/MyWebLog.Data.fsproj index 6b5d0a8..d2e5d31 100644 --- a/src/MyWebLog.Data/MyWebLog.Data.fsproj +++ b/src/MyWebLog.Data/MyWebLog.Data.fsproj @@ -9,7 +9,7 @@ - + diff --git a/src/MyWebLog.Data/Postgres/PostgresCache.fs b/src/MyWebLog.Data/Postgres/PostgresCache.fs index 4f665f5..2a8b9c8 100644 --- a/src/MyWebLog.Data/Postgres/PostgresCache.fs +++ b/src/MyWebLog.Data/Postgres/PostgresCache.fs @@ -2,7 +2,7 @@ namespace MyWebLog.Data.Postgres open System.Threading open System.Threading.Tasks -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Caching.Distributed open NodaTime @@ -48,9 +48,11 @@ type DistributedCache () = task { let! exists = Custom.scalar - $"SELECT EXISTS - (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session') - AS {existsName}" [] Map.toExists + "SELECT EXISTS + (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session') + AS it" + [] + toExists if not exists then do! Custom.nonQuery "CREATE TABLE session ( diff --git a/src/MyWebLog.Data/Postgres/PostgresCategoryData.fs b/src/MyWebLog.Data/Postgres/PostgresCategoryData.fs index ce12e88..d127585 100644 --- a/src/MyWebLog.Data/Postgres/PostgresCategoryData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresCategoryData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -41,13 +42,12 @@ type PostgresCategoryData(log: ILogger) = |> arrayContains (nameof Post.Empty.CategoryIds) id let postCount = Custom.scalar - $"""SELECT COUNT(DISTINCT data ->> '{nameof Post.Empty.Id}') AS {countName} + $"""SELECT COUNT(DISTINCT data ->> '{nameof Post.Empty.Id}') AS it FROM {Table.Post} WHERE {Query.whereDataContains "@criteria"} AND {catIdSql}""" - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |} - catIdParams ] - Map.toCount + [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catIdParams ] + toCount |> Async.AwaitTask |> Async.RunSynchronously it.Id, postCount) @@ -85,33 +85,32 @@ type PostgresCategoryData(log: ILogger) = Configuration.dataSource () |> Sql.fromDataSource |> Sql.executeTransactionAsync - [ Query.Update.partialById Table.Category, + [ Query.Patch.byId Table.Category, children |> List.map (fun child -> - [ "@id", Sql.string (string child.Id) - "@data", Query.jsonbDocParam {| ParentId = cat.ParentId |} ]) ] + [ idParam child.Id; jsonParam "@data" {| ParentId = cat.ParentId |} ]) ] () // Delete the category off all posts where it is assigned let! posts = Custom.list $"SELECT data FROM {Table.Post} WHERE data -> '{nameof Post.Empty.CategoryIds}' @> @id" - [ "@id", Query.jsonbDocParam [| string catId |] ] + [ jsonParam "@id" [| string catId |] ] fromData if not (List.isEmpty posts) then let! _ = Configuration.dataSource () |> Sql.fromDataSource |> Sql.executeTransactionAsync - [ Query.Update.partialById Table.Post, + [ Query.Patch.byId Table.Post, posts |> List.map (fun post -> - [ "@id", Sql.string (string post.Id) - "@data", Query.jsonbDocParam - {| CategoryIds = post.CategoryIds - |> List.filter (fun cat -> cat <> catId) |} ]) ] + [ idParam post.Id + jsonParam + "@data" + {| CategoryIds = post.CategoryIds |> List.filter (fun cat -> cat <> catId) |} ]) ] () // Delete the category itself - do! Delete.byId Table.Category (string catId) + do! Delete.byId Table.Category catId return if hasChildren then ReassignedChildCategories else CategoryDeleted | None -> return CategoryNotFound } @@ -129,7 +128,7 @@ type PostgresCategoryData(log: ILogger) = Configuration.dataSource () |> Sql.fromDataSource |> Sql.executeTransactionAsync [ - Query.insert Table.Category, cats |> List.map (fun c -> [ "@data", Query.jsonbDocParam c ]) + Query.insert Table.Category, cats |> List.map (fun c -> [ jsonParam "@data" c ]) ] () } diff --git a/src/MyWebLog.Data/Postgres/PostgresHelpers.fs b/src/MyWebLog.Data/Postgres/PostgresHelpers.fs index 601b1e8..b9e8bff 100644 --- a/src/MyWebLog.Data/Postgres/PostgresHelpers.fs +++ b/src/MyWebLog.Data/Postgres/PostgresHelpers.fs @@ -61,7 +61,8 @@ module Table = open System open System.Threading.Tasks -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open MyWebLog open MyWebLog.Data open NodaTime @@ -78,13 +79,7 @@ let webLogDoc (webLogId: WebLogId) = /// Create a parameter for a web log document-contains query let webLogContains webLogId = - "@criteria", Query.jsonbDocParam (webLogDoc webLogId) - -/// The name of the field to select to be able to use Map.toCount -let countName = "the_count" - -/// The name of the field to select to be able to use Map.toExists -let existsName = "does_exist" + jsonParam "@criteria" (webLogDoc webLogId) /// A SQL string to select data from a table with the given JSON document contains criteria let selectWithCriteria tableName = @@ -129,14 +124,6 @@ let optParam<'T> name (it: 'T option) = /// Mapping functions for SQL queries module Map = - /// Get a count from a row - let toCount (row: RowReader) = - row.int countName - - /// Get a true/false value as to whether an item exists - let toExists (row: RowReader) = - row.bool existsName - /// Create a permalink from the current row let toPermalink (row: RowReader) = Permalink (row.string "permalink") @@ -168,9 +155,9 @@ module Document = Custom.scalar $"""SELECT EXISTS ( SELECT 1 FROM %s{table} WHERE {Query.whereById "@id"} AND {Query.whereDataContains "@criteria"} - ) AS {existsName}""" + ) AS it""" [ "@id", Sql.string (string key); webLogContains webLogId ] - Map.toExists + toExists /// Find a document by its ID for the given web log let findByIdAndWebLog<'TKey, 'TDoc> table (key: 'TKey) webLogId = diff --git a/src/MyWebLog.Data/Postgres/PostgresPageData.fs b/src/MyWebLog.Data/Postgres/PostgresPageData.fs index 364a99f..33fb0e4 100644 --- a/src/MyWebLog.Data/Postgres/PostgresPageData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresPageData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -76,7 +77,7 @@ type PostgresPageData(log: ILogger) = do! Custom.nonQuery $"""DELETE FROM {Table.PageRevision} WHERE page_id = @id; DELETE FROM {Table.Page} WHERE {Query.whereById "@id"}""" - [ "@id", Sql.string (string pageId) ] + [ idParam pageId ] return true | false -> return false } @@ -119,7 +120,7 @@ type PostgresPageData(log: ILogger) = log.LogTrace "Page.findListed" Custom.list $"{selectWithCriteria Table.Page} ORDER BY LOWER(data ->> '{nameof Page.Empty.Title}')" - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with IsInPageList = true |} ] + [ jsonParam "@criteria" {| webLogDoc webLogId with IsInPageList = true |} ] pageWithoutText /// Get a page of pages for the given web log (without revisions) @@ -141,7 +142,7 @@ type PostgresPageData(log: ILogger) = |> Sql.fromDataSource |> Sql.executeTransactionAsync [ Query.insert Table.Page, - pages |> List.map (fun page -> [ "@data", Query.jsonbDocParam { page with Revisions = [] } ]) + pages |> List.map (fun page -> [ jsonParam "@data" { page with Revisions = [] } ]) Revisions.insertSql Table.PageRevision, revisions |> List.map (fun (pageId, rev) -> Revisions.revParams pageId rev) ] () @@ -161,7 +162,7 @@ type PostgresPageData(log: ILogger) = log.LogTrace "Page.updatePriorPermalinks" match! pageExists pageId webLogId with | true -> - do! Update.partialById Table.Page (string pageId) {| PriorPermalinks = permalinks |} + do! Patch.byId Table.Page pageId {| PriorPermalinks = permalinks |} return true | false -> return false } diff --git a/src/MyWebLog.Data/Postgres/PostgresPostData.fs b/src/MyWebLog.Data/Postgres/PostgresPostData.fs index b33abc6..6f858af 100644 --- a/src/MyWebLog.Data/Postgres/PostgresPostData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresPostData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -50,7 +51,7 @@ type PostgresPostData(log: ILogger) = log.LogTrace "Post.findByPermalink" Custom.single (selectWithCriteria Table.Post) - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Permalink = permalink |} ] + [ jsonParam "@criteria" {| webLogDoc webLogId with Permalink = permalink |} ] fromData /// Find a complete post by its ID for the given web log @@ -72,7 +73,7 @@ type PostgresPostData(log: ILogger) = $"""DELETE FROM {Table.PostComment} WHERE {Query.whereDataContains "@criteria"}; DELETE FROM {Table.PostRevision} WHERE post_id = @id; DELETE FROM {Table.Post} WHERE {Query.whereById "@id"}""" - [ "@id", Sql.string (string postId); "@criteria", Query.jsonbDocParam {| PostId = postId |} ] + [ idParam postId; jsonParam "@criteria" {| PostId = postId |} ] return true | false -> return false } @@ -113,7 +114,7 @@ type PostgresPostData(log: ILogger) = AND {catSql} ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}" - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |}; catParam ] + [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catParam ] fromData /// Get a page of posts for the given web log (excludes text and revisions) @@ -134,7 +135,7 @@ type PostgresPostData(log: ILogger) = $"{selectWithCriteria Table.Post} ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}" - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |} ] + [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ] fromData /// Get a page of tagged posts for the given web log (excludes revisions and prior permalinks) @@ -145,15 +146,14 @@ type PostgresPostData(log: ILogger) = AND data['{nameof Post.Empty.Tags}'] @> @tag ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}" - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |} - "@tag", Query.jsonbDocParam [| tag |] ] + [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; jsonParam "@tag" [| tag |] ] fromData /// Find the next newest and oldest post from a publish date for the given web log let findSurroundingPosts webLogId publishedOn = backgroundTask { log.LogTrace "Post.findSurroundingPosts" let queryParams () = - [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |} + [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} "@publishedOn", Sql.string ((InstantPattern.General.Format publishedOn)[..19]) ] let pubField = nameof Post.Empty.PublishedOn let! older = @@ -192,7 +192,7 @@ type PostgresPostData(log: ILogger) = |> Sql.fromDataSource |> Sql.executeTransactionAsync [ Query.insert Table.Post, - posts |> List.map (fun post -> [ "@data", Query.jsonbDocParam { post with Revisions = [] } ]) + posts |> List.map (fun post -> [ jsonParam "@data" { post with Revisions = [] } ]) Revisions.insertSql Table.PostRevision, revisions |> List.map (fun (postId, rev) -> Revisions.revParams postId rev) ] () @@ -203,7 +203,7 @@ type PostgresPostData(log: ILogger) = log.LogTrace "Post.updatePriorPermalinks" match! postExists postId webLogId with | true -> - do! Update.partialById Table.Post (string postId) {| PriorPermalinks = permalinks |} + do! Patch.byId Table.Post postId {| PriorPermalinks = permalinks |} return true | false -> return false } diff --git a/src/MyWebLog.Data/Postgres/PostgresTagMapData.fs b/src/MyWebLog.Data/Postgres/PostgresTagMapData.fs index 1a43b74..2369a6f 100644 --- a/src/MyWebLog.Data/Postgres/PostgresTagMapData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresTagMapData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -19,7 +20,7 @@ type PostgresTagMapData(log: ILogger) = log.LogTrace "TagMap.delete" let! exists = Document.existsByWebLog Table.TagMap tagMapId webLogId if exists then - do! Delete.byId Table.TagMap (string tagMapId) + do! Delete.byId Table.TagMap tagMapId return true else return false } @@ -58,7 +59,7 @@ type PostgresTagMapData(log: ILogger) = |> Sql.fromDataSource |> Sql.executeTransactionAsync [ Query.insert Table.TagMap, - tagMaps |> List.map (fun tagMap -> [ "@data", Query.jsonbDocParam tagMap ]) ] + tagMaps |> List.map (fun tagMap -> [ jsonParam "@data" tagMap ]) ] () } diff --git a/src/MyWebLog.Data/Postgres/PostgresThemeData.fs b/src/MyWebLog.Data/Postgres/PostgresThemeData.fs index 819489f..bb7d67d 100644 --- a/src/MyWebLog.Data/Postgres/PostgresThemeData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresThemeData.fs @@ -1,10 +1,10 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data -open Npgsql.FSharp /// PostreSQL myWebLog theme data implementation type PostgresThemeData(log: ILogger) = @@ -25,17 +25,17 @@ type PostgresThemeData(log: ILogger) = /// Does a given theme exist? let exists (themeId: ThemeId) = log.LogTrace "Theme.exists" - Exists.byId Table.Theme (string themeId) + Exists.byId Table.Theme themeId /// Find a theme by its ID let findById (themeId: ThemeId) = log.LogTrace "Theme.findById" - Find.byId Table.Theme (string themeId) + Find.byId Table.Theme themeId /// Find a theme by its ID (excludes the text of templates) let findByIdWithoutText (themeId: ThemeId) = log.LogTrace "Theme.findByIdWithoutText" - Custom.single (Query.Find.byId Table.Theme) [ "@id", Sql.string (string themeId) ] withoutTemplateText + Custom.single (Query.Find.byId Table.Theme) [ idParam themeId ] withoutTemplateText /// Delete a theme by its ID let delete themeId = backgroundTask { @@ -45,7 +45,7 @@ type PostgresThemeData(log: ILogger) = do! Custom.nonQuery $"""DELETE FROM {Table.ThemeAsset} WHERE theme_id = @id; DELETE FROM {Table.Theme} WHERE {Query.whereById "@id"}""" - [ "@id", Sql.string (string themeId) ] + [ idParam themeId ] return true | false -> return false } @@ -75,32 +75,29 @@ type PostgresThemeAssetData(log: ILogger) = /// Delete all assets for the given theme let deleteByTheme (themeId: ThemeId) = log.LogTrace "ThemeAsset.deleteByTheme" - Custom.nonQuery $"DELETE FROM {Table.ThemeAsset} WHERE theme_id = @id" [ "@id", Sql.string (string themeId) ] + Custom.nonQuery $"DELETE FROM {Table.ThemeAsset} WHERE theme_id = @id" [ idParam themeId ] /// Find a theme asset by its ID let findById assetId = log.LogTrace "ThemeAsset.findById" let (ThemeAssetId (ThemeId themeId, path)) = assetId Custom.single - $"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @themeId AND path = @path" - [ "@themeId", Sql.string themeId; "@path", Sql.string path ] + $"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @id AND path = @path" + [ idParam themeId; "@path", Sql.string path ] (Map.toThemeAsset true) /// Get theme assets for the given theme (excludes data) let findByTheme (themeId: ThemeId) = log.LogTrace "ThemeAsset.findByTheme" Custom.list - $"SELECT theme_id, path, updated_on FROM {Table.ThemeAsset} WHERE theme_id = @themeId" - [ "@themeId", Sql.string (string themeId) ] + $"SELECT theme_id, path, updated_on FROM {Table.ThemeAsset} WHERE theme_id = @id" + [ idParam themeId ] (Map.toThemeAsset false) /// Get theme assets for the given theme let findByThemeWithData (themeId: ThemeId) = log.LogTrace "ThemeAsset.findByThemeWithData" - Custom.list - $"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @themeId" - [ "@themeId", Sql.string (string themeId) ] - (Map.toThemeAsset true) + Custom.list $"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @id" [ idParam themeId ] (Map.toThemeAsset true) /// Save a theme asset let save (asset: ThemeAsset) = diff --git a/src/MyWebLog.Data/Postgres/PostgresUploadData.fs b/src/MyWebLog.Data/Postgres/PostgresUploadData.fs index f78c0f3..bfacbc9 100644 --- a/src/MyWebLog.Data/Postgres/PostgresUploadData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresUploadData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -21,7 +22,7 @@ type PostgresUploadData(log: ILogger) = let upParams (upload: Upload) = [ webLogIdParam upload.WebLogId typedParam "updatedOn" upload.UpdatedOn - "@id", Sql.string (string upload.Id) + idParam upload.Id "@path", Sql.string (string upload.Path) "@data", Sql.bytea upload.Data ] @@ -33,7 +34,7 @@ type PostgresUploadData(log: ILogger) = /// Delete an uploaded file by its ID let delete uploadId webLogId = backgroundTask { log.LogTrace "Upload.delete" - let idParam = [ "@id", Sql.string (string uploadId) ] + let idParam = [ idParam uploadId ] let! path = Custom.single $"SELECT path FROM {Table.Upload} WHERE id = @id AND web_log_id = @webLogId" diff --git a/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs b/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs index 60ed13c..921fd67 100644 --- a/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -46,13 +47,13 @@ type PostgresWebLogData(log: ILogger) = /// Find a web log by its ID let findById (webLogId: WebLogId) = log.LogTrace "WebLog.findById" - Find.byId Table.WebLog (string webLogId) + Find.byId Table.WebLog webLogId /// Update redirect rules for a web log let updateRedirectRules (webLog: WebLog) = backgroundTask { log.LogTrace "WebLog.updateRedirectRules" match! findById webLog.Id with - | Some _ -> do! Update.partialById Table.WebLog (string webLog.Id) {| RedirectRules = webLog.RedirectRules |} + | Some _ -> do! Patch.byId Table.WebLog webLog.Id {| RedirectRules = webLog.RedirectRules |} | None -> () } @@ -60,14 +61,14 @@ type PostgresWebLogData(log: ILogger) = let updateRssOptions (webLog: WebLog) = backgroundTask { log.LogTrace "WebLog.updateRssOptions" match! findById webLog.Id with - | Some _ -> do! Update.partialById Table.WebLog (string webLog.Id) {| Rss = webLog.Rss |} + | Some _ -> do! Patch.byId Table.WebLog webLog.Id {| Rss = webLog.Rss |} | None -> () } /// Update settings for a web log let updateSettings (webLog: WebLog) = log.LogTrace "WebLog.updateSettings" - Update.full Table.WebLog (string webLog.Id) webLog + Update.byId Table.WebLog webLog.Id webLog interface IWebLogData with member _.Add webLog = add webLog diff --git a/src/MyWebLog.Data/Postgres/PostgresWebLogUserData.fs b/src/MyWebLog.Data/Postgres/PostgresWebLogUserData.fs index ed7f08c..d919d12 100644 --- a/src/MyWebLog.Data/Postgres/PostgresWebLogUserData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresWebLogUserData.fs @@ -1,6 +1,7 @@ namespace MyWebLog.Data.Postgres -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data @@ -24,13 +25,13 @@ type PostgresWebLogUserData(log: ILogger) = Custom.scalar $" SELECT ( EXISTS (SELECT 1 FROM {Table.Page} WHERE {criteria}) OR EXISTS (SELECT 1 FROM {Table.Post} WHERE {criteria}) - ) AS {existsName}" - [ "@criteria", Query.jsonbDocParam {| AuthorId = userId |} ] - Map.toExists + ) AS it" + [ jsonParam "@criteria" {| AuthorId = userId |} ] + toExists if isAuthor then return Error "User has pages or posts; cannot delete" else - do! Delete.byId Table.WebLogUser (string userId) + do! Delete.byId Table.WebLogUser userId return Ok true | None -> return Error "User does not exist" } @@ -67,8 +68,7 @@ type PostgresWebLogUserData(log: ILogger) = Configuration.dataSource () |> Sql.fromDataSource |> Sql.executeTransactionAsync - [ Query.insert Table.WebLogUser, - users |> List.map (fun user -> Query.docParameters (string user.Id) user) ] + [ Query.insert Table.WebLogUser, users |> List.map (fun user -> [ jsonParam "@data" user ]) ] () } @@ -76,7 +76,7 @@ type PostgresWebLogUserData(log: ILogger) = let setLastSeen (userId: WebLogUserId) webLogId = backgroundTask { log.LogTrace "WebLogUser.setLastSeen" match! Document.existsByWebLog Table.WebLogUser userId webLogId with - | true -> do! Update.partialById Table.WebLogUser (string userId) {| LastSeenOn = Some (Noda.now ()) |} + | true -> do! Patch.byId Table.WebLogUser userId {| LastSeenOn = Some (Noda.now ()) |} | false -> () } diff --git a/src/MyWebLog.Data/PostgresData.fs b/src/MyWebLog.Data/PostgresData.fs index 09e4207..b35ec62 100644 --- a/src/MyWebLog.Data/PostgresData.fs +++ b/src/MyWebLog.Data/PostgresData.fs @@ -1,7 +1,7 @@ namespace MyWebLog.Data -open BitBadger.Npgsql.Documents -open BitBadger.Npgsql.FSharp.Documents +open BitBadger.Documents +open BitBadger.Documents.Postgres open Microsoft.Extensions.Logging open MyWebLog open MyWebLog.Data.Postgres @@ -31,8 +31,8 @@ type PostgresData(log: ILogger, ser: JsonSerializer) = // Theme tables if needsTable Table.Theme then isNew <- true - Definition.createTable Table.Theme - Definition.createKey Table.Theme + Query.Definition.ensureTable Table.Theme + Query.Definition.ensureKey Table.Theme if needsTable Table.ThemeAsset then $"CREATE TABLE {Table.ThemeAsset} ( theme_id TEXT NOT NULL, @@ -43,30 +43,29 @@ type PostgresData(log: ILogger, ser: JsonSerializer) = // Web log table if needsTable Table.WebLog then - Definition.createTable Table.WebLog - Definition.createKey Table.WebLog - Definition.createIndex Table.WebLog Optimized + Query.Definition.ensureTable Table.WebLog + Query.Definition.ensureKey Table.WebLog + Query.Definition.ensureDocumentIndex Table.WebLog Optimized // Category table if needsTable Table.Category then - Definition.createTable Table.Category - Definition.createKey Table.Category - Definition.createIndex Table.Category Optimized + Query.Definition.ensureTable Table.Category + Query.Definition.ensureKey Table.Category + Query.Definition.ensureDocumentIndex Table.Category Optimized // Web log user table if needsTable Table.WebLogUser then - Definition.createTable Table.WebLogUser - Definition.createKey Table.WebLogUser - Definition.createIndex Table.WebLogUser Optimized + Query.Definition.ensureTable Table.WebLogUser + Query.Definition.ensureKey Table.WebLogUser + Query.Definition.ensureDocumentIndex Table.WebLogUser Optimized // Page tables if needsTable Table.Page then - Definition.createTable Table.Page - Definition.createKey Table.Page - $"CREATE INDEX page_web_log_idx ON {Table.Page} ((data ->> '{nameof Page.Empty.WebLogId}'))" - $"CREATE INDEX page_author_idx ON {Table.Page} ((data ->> '{nameof Page.Empty.AuthorId}'))" - $"CREATE INDEX page_permalink_idx ON {Table.Page} - ((data ->> '{nameof Page.Empty.WebLogId}'), (data ->> '{nameof Page.Empty.Permalink}'))" + Query.Definition.ensureTable Table.Page + Query.Definition.ensureKey Table.Page + Query.Definition.ensureIndexOn Table.Page "author" [ nameof Page.Empty.AuthorId ] + Query.Definition.ensureIndexOn + Table.Page "permalink" [ nameof Page.Empty.WebLogId; nameof Page.Empty.Permalink ] if needsTable Table.PageRevision then $"CREATE TABLE {Table.PageRevision} ( page_id TEXT NOT NULL, @@ -76,15 +75,15 @@ type PostgresData(log: ILogger, ser: JsonSerializer) = // Post tables if needsTable Table.Post then - Definition.createTable Table.Post - Definition.createKey Table.Post - $"CREATE INDEX post_web_log_idx ON {Table.Post} ((data ->> '{nameof Post.Empty.WebLogId}'))" - $"CREATE INDEX post_author_idx ON {Table.Post} ((data ->> '{nameof Post.Empty.AuthorId}'))" - $"CREATE INDEX post_status_idx ON {Table.Post} - ((data ->> '{nameof Post.Empty.WebLogId}'), (data ->> '{nameof Post.Empty.Status}'), - (data ->> '{nameof Post.Empty.UpdatedOn}'))" - $"CREATE INDEX post_permalink_idx ON {Table.Post} - ((data ->> '{nameof Post.Empty.WebLogId}'), (data ->> '{nameof Post.Empty.Permalink}'))" + Query.Definition.ensureTable Table.Post + Query.Definition.ensureKey Table.Post + Query.Definition.ensureIndexOn Table.Post "author" [ nameof Post.Empty.AuthorId ] + Query.Definition.ensureIndexOn + Table.Post "permalink" [ nameof Post.Empty.WebLogId; nameof Post.Empty.Permalink ] + Query.Definition.ensureIndexOn + Table.Post + "status" + [ nameof Post.Empty.WebLogId; nameof Post.Empty.Status; nameof Post.Empty.UpdatedOn ] $"CREATE INDEX post_category_idx ON {Table.Post} USING GIN ((data['{nameof Post.Empty.CategoryIds}']))" $"CREATE INDEX post_tag_idx ON {Table.Post} USING GIN ((data['{nameof Post.Empty.Tags}']))" if needsTable Table.PostRevision then @@ -94,16 +93,15 @@ type PostgresData(log: ILogger, ser: JsonSerializer) = revision_text TEXT NOT NULL, PRIMARY KEY (post_id, as_of))" if needsTable Table.PostComment then - Definition.createTable Table.PostComment - Definition.createKey Table.PostComment - $"CREATE INDEX post_comment_post_idx ON {Table.PostComment} - ((data ->> '{nameof Comment.Empty.PostId}'))" + Query.Definition.ensureTable Table.PostComment + Query.Definition.ensureKey Table.PostComment + Query.Definition.ensureIndexOn Table.PostComment "post" [ nameof Comment.Empty.PostId ] // Tag map table if needsTable Table.TagMap then - Definition.createTable Table.TagMap - Definition.createKey Table.TagMap - Definition.createIndex Table.TagMap Optimized + Query.Definition.ensureTable Table.TagMap + Query.Definition.ensureKey Table.TagMap + Query.Definition.ensureDocumentIndex Table.TagMap Optimized // Uploaded file table if needsTable Table.Upload then diff --git a/src/MyWebLog/Program.fs b/src/MyWebLog/Program.fs index 5de9065..e8c7380 100644 --- a/src/MyWebLog/Program.fs +++ b/src/MyWebLog/Program.fs @@ -50,14 +50,12 @@ type RedirectRuleMiddleware(next: RequestDelegate, log: ILogger