Migrate Postgres data to new library

This commit is contained in:
Daniel J. Summers 2023-12-31 08:36:03 -05:00
parent 7fb68d5583
commit e8d63793ba
13 changed files with 111 additions and 126 deletions

View File

@ -9,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BitBadger.Npgsql.FSharp.Documents" Version="2.0.0" />
<PackageReference Include="BitBadger.Documents.Postgres" Version="3.0.0-rc-1" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />

View File

@ -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 EXISTS
(SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session')
AS {existsName}" [] Map.toExists
AS it"
[]
toExists
if not exists then
do! Custom.nonQuery
"CREATE TABLE session (

View File

@ -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<Post>
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 ])
]
()
}

View File

@ -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 =

View File

@ -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
}

View File

@ -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<Post>
/// 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<Post>
/// 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<Post>
/// 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<Post>
/// 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
}

View File

@ -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 ]) ]
()
}

View File

@ -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<Theme> Table.Theme (string themeId)
Find.byId<ThemeId, Theme> 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) =

View File

@ -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"

View File

@ -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<WebLog> Table.WebLog (string webLogId)
Find.byId<WebLogId, WebLog> 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

View File

@ -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 -> ()
}

View File

@ -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<PostgresData>, 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<PostgresData>, 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<PostgresData>, 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<PostgresData>, 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

View File

@ -50,14 +50,12 @@ type RedirectRuleMiddleware(next: RequestDelegate, log: ILogger<RedirectRuleMidd
open System
open BitBadger.Documents
open Microsoft.Extensions.DependencyInjection
open MyWebLog.Data
open Newtonsoft.Json
open Npgsql
// The PostgreSQL document library
module Postgres = BitBadger.Npgsql.FSharp.Documents
// The SQLite document library
module Sqlite = BitBadger.Sqlite.FSharp.Documents