Migrate Postgres data to new library
This commit is contained in:
parent
7fb68d5583
commit
e8d63793ba
@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<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.Data.Sqlite" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||||
|
@ -2,7 +2,7 @@ namespace MyWebLog.Data.Postgres
|
|||||||
|
|
||||||
open System.Threading
|
open System.Threading
|
||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Caching.Distributed
|
open Microsoft.Extensions.Caching.Distributed
|
||||||
open NodaTime
|
open NodaTime
|
||||||
|
|
||||||
@ -48,9 +48,11 @@ type DistributedCache () =
|
|||||||
task {
|
task {
|
||||||
let! exists =
|
let! exists =
|
||||||
Custom.scalar
|
Custom.scalar
|
||||||
$"SELECT EXISTS
|
"SELECT EXISTS
|
||||||
(SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session')
|
(SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session')
|
||||||
AS {existsName}" [] Map.toExists
|
AS it"
|
||||||
|
[]
|
||||||
|
toExists
|
||||||
if not exists then
|
if not exists then
|
||||||
do! Custom.nonQuery
|
do! Custom.nonQuery
|
||||||
"CREATE TABLE session (
|
"CREATE TABLE session (
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -41,13 +42,12 @@ type PostgresCategoryData(log: ILogger) =
|
|||||||
|> arrayContains (nameof Post.Empty.CategoryIds) id
|
|> arrayContains (nameof Post.Empty.CategoryIds) id
|
||||||
let postCount =
|
let postCount =
|
||||||
Custom.scalar
|
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}
|
FROM {Table.Post}
|
||||||
WHERE {Query.whereDataContains "@criteria"}
|
WHERE {Query.whereDataContains "@criteria"}
|
||||||
AND {catIdSql}"""
|
AND {catIdSql}"""
|
||||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |}
|
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catIdParams ]
|
||||||
catIdParams ]
|
toCount
|
||||||
Map.toCount
|
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.RunSynchronously
|
|> Async.RunSynchronously
|
||||||
it.Id, postCount)
|
it.Id, postCount)
|
||||||
@ -85,33 +85,32 @@ type PostgresCategoryData(log: ILogger) =
|
|||||||
Configuration.dataSource ()
|
Configuration.dataSource ()
|
||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.Update.partialById Table.Category,
|
[ Query.Patch.byId Table.Category,
|
||||||
children
|
children
|
||||||
|> List.map (fun child ->
|
|> List.map (fun child ->
|
||||||
[ "@id", Sql.string (string child.Id)
|
[ idParam child.Id; jsonParam "@data" {| ParentId = cat.ParentId |} ]) ]
|
||||||
"@data", Query.jsonbDocParam {| ParentId = cat.ParentId |} ]) ]
|
|
||||||
()
|
()
|
||||||
// Delete the category off all posts where it is assigned
|
// Delete the category off all posts where it is assigned
|
||||||
let! posts =
|
let! posts =
|
||||||
Custom.list
|
Custom.list
|
||||||
$"SELECT data FROM {Table.Post} WHERE data -> '{nameof Post.Empty.CategoryIds}' @> @id"
|
$"SELECT data FROM {Table.Post} WHERE data -> '{nameof Post.Empty.CategoryIds}' @> @id"
|
||||||
[ "@id", Query.jsonbDocParam [| string catId |] ]
|
[ jsonParam "@id" [| string catId |] ]
|
||||||
fromData<Post>
|
fromData<Post>
|
||||||
if not (List.isEmpty posts) then
|
if not (List.isEmpty posts) then
|
||||||
let! _ =
|
let! _ =
|
||||||
Configuration.dataSource ()
|
Configuration.dataSource ()
|
||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.Update.partialById Table.Post,
|
[ Query.Patch.byId Table.Post,
|
||||||
posts
|
posts
|
||||||
|> List.map (fun post ->
|
|> List.map (fun post ->
|
||||||
[ "@id", Sql.string (string post.Id)
|
[ idParam post.Id
|
||||||
"@data", Query.jsonbDocParam
|
jsonParam
|
||||||
{| CategoryIds = post.CategoryIds
|
"@data"
|
||||||
|> List.filter (fun cat -> cat <> catId) |} ]) ]
|
{| CategoryIds = post.CategoryIds |> List.filter (fun cat -> cat <> catId) |} ]) ]
|
||||||
()
|
()
|
||||||
// Delete the category itself
|
// Delete the category itself
|
||||||
do! Delete.byId Table.Category (string catId)
|
do! Delete.byId Table.Category catId
|
||||||
return if hasChildren then ReassignedChildCategories else CategoryDeleted
|
return if hasChildren then ReassignedChildCategories else CategoryDeleted
|
||||||
| None -> return CategoryNotFound
|
| None -> return CategoryNotFound
|
||||||
}
|
}
|
||||||
@ -129,7 +128,7 @@ type PostgresCategoryData(log: ILogger) =
|
|||||||
Configuration.dataSource ()
|
Configuration.dataSource ()
|
||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync [
|
|> 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 ])
|
||||||
]
|
]
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ module Table =
|
|||||||
|
|
||||||
open System
|
open System
|
||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
open NodaTime
|
open NodaTime
|
||||||
@ -78,13 +79,7 @@ let webLogDoc (webLogId: WebLogId) =
|
|||||||
|
|
||||||
/// Create a parameter for a web log document-contains query
|
/// Create a parameter for a web log document-contains query
|
||||||
let webLogContains webLogId =
|
let webLogContains webLogId =
|
||||||
"@criteria", Query.jsonbDocParam (webLogDoc webLogId)
|
jsonParam "@criteria" (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"
|
|
||||||
|
|
||||||
/// A SQL string to select data from a table with the given JSON document contains criteria
|
/// A SQL string to select data from a table with the given JSON document contains criteria
|
||||||
let selectWithCriteria tableName =
|
let selectWithCriteria tableName =
|
||||||
@ -129,14 +124,6 @@ let optParam<'T> name (it: 'T option) =
|
|||||||
/// Mapping functions for SQL queries
|
/// Mapping functions for SQL queries
|
||||||
module Map =
|
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
|
/// Create a permalink from the current row
|
||||||
let toPermalink (row: RowReader) =
|
let toPermalink (row: RowReader) =
|
||||||
Permalink (row.string "permalink")
|
Permalink (row.string "permalink")
|
||||||
@ -168,9 +155,9 @@ module Document =
|
|||||||
Custom.scalar
|
Custom.scalar
|
||||||
$"""SELECT EXISTS (
|
$"""SELECT EXISTS (
|
||||||
SELECT 1 FROM %s{table} WHERE {Query.whereById "@id"} AND {Query.whereDataContains "@criteria"}
|
SELECT 1 FROM %s{table} WHERE {Query.whereById "@id"} AND {Query.whereDataContains "@criteria"}
|
||||||
) AS {existsName}"""
|
) AS it"""
|
||||||
[ "@id", Sql.string (string key); webLogContains webLogId ]
|
[ "@id", Sql.string (string key); webLogContains webLogId ]
|
||||||
Map.toExists
|
toExists
|
||||||
|
|
||||||
/// Find a document by its ID for the given web log
|
/// Find a document by its ID for the given web log
|
||||||
let findByIdAndWebLog<'TKey, 'TDoc> table (key: 'TKey) webLogId =
|
let findByIdAndWebLog<'TKey, 'TDoc> table (key: 'TKey) webLogId =
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -76,7 +77,7 @@ type PostgresPageData(log: ILogger) =
|
|||||||
do! Custom.nonQuery
|
do! Custom.nonQuery
|
||||||
$"""DELETE FROM {Table.PageRevision} WHERE page_id = @id;
|
$"""DELETE FROM {Table.PageRevision} WHERE page_id = @id;
|
||||||
DELETE FROM {Table.Page} WHERE {Query.whereById "@id"}"""
|
DELETE FROM {Table.Page} WHERE {Query.whereById "@id"}"""
|
||||||
[ "@id", Sql.string (string pageId) ]
|
[ idParam pageId ]
|
||||||
return true
|
return true
|
||||||
| false -> return false
|
| false -> return false
|
||||||
}
|
}
|
||||||
@ -119,7 +120,7 @@ type PostgresPageData(log: ILogger) =
|
|||||||
log.LogTrace "Page.findListed"
|
log.LogTrace "Page.findListed"
|
||||||
Custom.list
|
Custom.list
|
||||||
$"{selectWithCriteria Table.Page} ORDER BY LOWER(data ->> '{nameof Page.Empty.Title}')"
|
$"{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
|
pageWithoutText
|
||||||
|
|
||||||
/// Get a page of pages for the given web log (without revisions)
|
/// Get a page of pages for the given web log (without revisions)
|
||||||
@ -141,7 +142,7 @@ type PostgresPageData(log: ILogger) =
|
|||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.insert Table.Page,
|
[ 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.insertSql Table.PageRevision,
|
||||||
revisions |> List.map (fun (pageId, rev) -> Revisions.revParams pageId rev) ]
|
revisions |> List.map (fun (pageId, rev) -> Revisions.revParams pageId rev) ]
|
||||||
()
|
()
|
||||||
@ -161,7 +162,7 @@ type PostgresPageData(log: ILogger) =
|
|||||||
log.LogTrace "Page.updatePriorPermalinks"
|
log.LogTrace "Page.updatePriorPermalinks"
|
||||||
match! pageExists pageId webLogId with
|
match! pageExists pageId webLogId with
|
||||||
| true ->
|
| true ->
|
||||||
do! Update.partialById Table.Page (string pageId) {| PriorPermalinks = permalinks |}
|
do! Patch.byId Table.Page pageId {| PriorPermalinks = permalinks |}
|
||||||
return true
|
return true
|
||||||
| false -> return false
|
| false -> return false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -50,7 +51,7 @@ type PostgresPostData(log: ILogger) =
|
|||||||
log.LogTrace "Post.findByPermalink"
|
log.LogTrace "Post.findByPermalink"
|
||||||
Custom.single
|
Custom.single
|
||||||
(selectWithCriteria Table.Post)
|
(selectWithCriteria Table.Post)
|
||||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Permalink = permalink |} ]
|
[ jsonParam "@criteria" {| webLogDoc webLogId with Permalink = permalink |} ]
|
||||||
fromData<Post>
|
fromData<Post>
|
||||||
|
|
||||||
/// Find a complete post by its ID for the given web log
|
/// 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.PostComment} WHERE {Query.whereDataContains "@criteria"};
|
||||||
DELETE FROM {Table.PostRevision} WHERE post_id = @id;
|
DELETE FROM {Table.PostRevision} WHERE post_id = @id;
|
||||||
DELETE FROM {Table.Post} WHERE {Query.whereById "@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
|
return true
|
||||||
| false -> return false
|
| false -> return false
|
||||||
}
|
}
|
||||||
@ -113,7 +114,7 @@ type PostgresPostData(log: ILogger) =
|
|||||||
AND {catSql}
|
AND {catSql}
|
||||||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
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>
|
fromData<Post>
|
||||||
|
|
||||||
/// Get a page of posts for the given web log (excludes text and revisions)
|
/// 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}
|
$"{selectWithCriteria Table.Post}
|
||||||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |} ]
|
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ]
|
||||||
fromData<Post>
|
fromData<Post>
|
||||||
|
|
||||||
/// Get a page of tagged posts for the given web log (excludes revisions and prior permalinks)
|
/// 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
|
AND data['{nameof Post.Empty.Tags}'] @> @tag
|
||||||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = Published |}
|
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; jsonParam "@tag" [| tag |] ]
|
||||||
"@tag", Query.jsonbDocParam [| tag |] ]
|
|
||||||
fromData<Post>
|
fromData<Post>
|
||||||
|
|
||||||
/// Find the next newest and oldest post from a publish date for the given web log
|
/// Find the next newest and oldest post from a publish date for the given web log
|
||||||
let findSurroundingPosts webLogId publishedOn = backgroundTask {
|
let findSurroundingPosts webLogId publishedOn = backgroundTask {
|
||||||
log.LogTrace "Post.findSurroundingPosts"
|
log.LogTrace "Post.findSurroundingPosts"
|
||||||
let queryParams () =
|
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]) ]
|
"@publishedOn", Sql.string ((InstantPattern.General.Format publishedOn)[..19]) ]
|
||||||
let pubField = nameof Post.Empty.PublishedOn
|
let pubField = nameof Post.Empty.PublishedOn
|
||||||
let! older =
|
let! older =
|
||||||
@ -192,7 +192,7 @@ type PostgresPostData(log: ILogger) =
|
|||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.insert Table.Post,
|
[ 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.insertSql Table.PostRevision,
|
||||||
revisions |> List.map (fun (postId, rev) -> Revisions.revParams postId rev) ]
|
revisions |> List.map (fun (postId, rev) -> Revisions.revParams postId rev) ]
|
||||||
()
|
()
|
||||||
@ -203,7 +203,7 @@ type PostgresPostData(log: ILogger) =
|
|||||||
log.LogTrace "Post.updatePriorPermalinks"
|
log.LogTrace "Post.updatePriorPermalinks"
|
||||||
match! postExists postId webLogId with
|
match! postExists postId webLogId with
|
||||||
| true ->
|
| true ->
|
||||||
do! Update.partialById Table.Post (string postId) {| PriorPermalinks = permalinks |}
|
do! Patch.byId Table.Post postId {| PriorPermalinks = permalinks |}
|
||||||
return true
|
return true
|
||||||
| false -> return false
|
| false -> return false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -19,7 +20,7 @@ type PostgresTagMapData(log: ILogger) =
|
|||||||
log.LogTrace "TagMap.delete"
|
log.LogTrace "TagMap.delete"
|
||||||
let! exists = Document.existsByWebLog Table.TagMap tagMapId webLogId
|
let! exists = Document.existsByWebLog Table.TagMap tagMapId webLogId
|
||||||
if exists then
|
if exists then
|
||||||
do! Delete.byId Table.TagMap (string tagMapId)
|
do! Delete.byId Table.TagMap tagMapId
|
||||||
return true
|
return true
|
||||||
else return false
|
else return false
|
||||||
}
|
}
|
||||||
@ -58,7 +59,7 @@ type PostgresTagMapData(log: ILogger) =
|
|||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.insert Table.TagMap,
|
[ Query.insert Table.TagMap,
|
||||||
tagMaps |> List.map (fun tagMap -> [ "@data", Query.jsonbDocParam tagMap ]) ]
|
tagMaps |> List.map (fun tagMap -> [ jsonParam "@data" tagMap ]) ]
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
open Npgsql.FSharp
|
|
||||||
|
|
||||||
/// PostreSQL myWebLog theme data implementation
|
/// PostreSQL myWebLog theme data implementation
|
||||||
type PostgresThemeData(log: ILogger) =
|
type PostgresThemeData(log: ILogger) =
|
||||||
@ -25,17 +25,17 @@ type PostgresThemeData(log: ILogger) =
|
|||||||
/// Does a given theme exist?
|
/// Does a given theme exist?
|
||||||
let exists (themeId: ThemeId) =
|
let exists (themeId: ThemeId) =
|
||||||
log.LogTrace "Theme.exists"
|
log.LogTrace "Theme.exists"
|
||||||
Exists.byId Table.Theme (string themeId)
|
Exists.byId Table.Theme themeId
|
||||||
|
|
||||||
/// Find a theme by its ID
|
/// Find a theme by its ID
|
||||||
let findById (themeId: ThemeId) =
|
let findById (themeId: ThemeId) =
|
||||||
log.LogTrace "Theme.findById"
|
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)
|
/// Find a theme by its ID (excludes the text of templates)
|
||||||
let findByIdWithoutText (themeId: ThemeId) =
|
let findByIdWithoutText (themeId: ThemeId) =
|
||||||
log.LogTrace "Theme.findByIdWithoutText"
|
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
|
/// Delete a theme by its ID
|
||||||
let delete themeId = backgroundTask {
|
let delete themeId = backgroundTask {
|
||||||
@ -45,7 +45,7 @@ type PostgresThemeData(log: ILogger) =
|
|||||||
do! Custom.nonQuery
|
do! Custom.nonQuery
|
||||||
$"""DELETE FROM {Table.ThemeAsset} WHERE theme_id = @id;
|
$"""DELETE FROM {Table.ThemeAsset} WHERE theme_id = @id;
|
||||||
DELETE FROM {Table.Theme} WHERE {Query.whereById "@id"}"""
|
DELETE FROM {Table.Theme} WHERE {Query.whereById "@id"}"""
|
||||||
[ "@id", Sql.string (string themeId) ]
|
[ idParam themeId ]
|
||||||
return true
|
return true
|
||||||
| false -> return false
|
| false -> return false
|
||||||
}
|
}
|
||||||
@ -75,32 +75,29 @@ type PostgresThemeAssetData(log: ILogger) =
|
|||||||
/// Delete all assets for the given theme
|
/// Delete all assets for the given theme
|
||||||
let deleteByTheme (themeId: ThemeId) =
|
let deleteByTheme (themeId: ThemeId) =
|
||||||
log.LogTrace "ThemeAsset.deleteByTheme"
|
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
|
/// Find a theme asset by its ID
|
||||||
let findById assetId =
|
let findById assetId =
|
||||||
log.LogTrace "ThemeAsset.findById"
|
log.LogTrace "ThemeAsset.findById"
|
||||||
let (ThemeAssetId (ThemeId themeId, path)) = assetId
|
let (ThemeAssetId (ThemeId themeId, path)) = assetId
|
||||||
Custom.single
|
Custom.single
|
||||||
$"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @themeId AND path = @path"
|
$"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @id AND path = @path"
|
||||||
[ "@themeId", Sql.string themeId; "@path", Sql.string path ]
|
[ idParam themeId; "@path", Sql.string path ]
|
||||||
(Map.toThemeAsset true)
|
(Map.toThemeAsset true)
|
||||||
|
|
||||||
/// Get theme assets for the given theme (excludes data)
|
/// Get theme assets for the given theme (excludes data)
|
||||||
let findByTheme (themeId: ThemeId) =
|
let findByTheme (themeId: ThemeId) =
|
||||||
log.LogTrace "ThemeAsset.findByTheme"
|
log.LogTrace "ThemeAsset.findByTheme"
|
||||||
Custom.list
|
Custom.list
|
||||||
$"SELECT theme_id, path, updated_on FROM {Table.ThemeAsset} WHERE theme_id = @themeId"
|
$"SELECT theme_id, path, updated_on FROM {Table.ThemeAsset} WHERE theme_id = @id"
|
||||||
[ "@themeId", Sql.string (string themeId) ]
|
[ idParam themeId ]
|
||||||
(Map.toThemeAsset false)
|
(Map.toThemeAsset false)
|
||||||
|
|
||||||
/// Get theme assets for the given theme
|
/// Get theme assets for the given theme
|
||||||
let findByThemeWithData (themeId: ThemeId) =
|
let findByThemeWithData (themeId: ThemeId) =
|
||||||
log.LogTrace "ThemeAsset.findByThemeWithData"
|
log.LogTrace "ThemeAsset.findByThemeWithData"
|
||||||
Custom.list
|
Custom.list $"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @id" [ idParam themeId ] (Map.toThemeAsset true)
|
||||||
$"SELECT * FROM {Table.ThemeAsset} WHERE theme_id = @themeId"
|
|
||||||
[ "@themeId", Sql.string (string themeId) ]
|
|
||||||
(Map.toThemeAsset true)
|
|
||||||
|
|
||||||
/// Save a theme asset
|
/// Save a theme asset
|
||||||
let save (asset: ThemeAsset) =
|
let save (asset: ThemeAsset) =
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -21,7 +22,7 @@ type PostgresUploadData(log: ILogger) =
|
|||||||
let upParams (upload: Upload) =
|
let upParams (upload: Upload) =
|
||||||
[ webLogIdParam upload.WebLogId
|
[ webLogIdParam upload.WebLogId
|
||||||
typedParam "updatedOn" upload.UpdatedOn
|
typedParam "updatedOn" upload.UpdatedOn
|
||||||
"@id", Sql.string (string upload.Id)
|
idParam upload.Id
|
||||||
"@path", Sql.string (string upload.Path)
|
"@path", Sql.string (string upload.Path)
|
||||||
"@data", Sql.bytea upload.Data ]
|
"@data", Sql.bytea upload.Data ]
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ type PostgresUploadData(log: ILogger) =
|
|||||||
/// Delete an uploaded file by its ID
|
/// Delete an uploaded file by its ID
|
||||||
let delete uploadId webLogId = backgroundTask {
|
let delete uploadId webLogId = backgroundTask {
|
||||||
log.LogTrace "Upload.delete"
|
log.LogTrace "Upload.delete"
|
||||||
let idParam = [ "@id", Sql.string (string uploadId) ]
|
let idParam = [ idParam uploadId ]
|
||||||
let! path =
|
let! path =
|
||||||
Custom.single
|
Custom.single
|
||||||
$"SELECT path FROM {Table.Upload} WHERE id = @id AND web_log_id = @webLogId"
|
$"SELECT path FROM {Table.Upload} WHERE id = @id AND web_log_id = @webLogId"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -46,13 +47,13 @@ type PostgresWebLogData(log: ILogger) =
|
|||||||
/// Find a web log by its ID
|
/// Find a web log by its ID
|
||||||
let findById (webLogId: WebLogId) =
|
let findById (webLogId: WebLogId) =
|
||||||
log.LogTrace "WebLog.findById"
|
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
|
/// Update redirect rules for a web log
|
||||||
let updateRedirectRules (webLog: WebLog) = backgroundTask {
|
let updateRedirectRules (webLog: WebLog) = backgroundTask {
|
||||||
log.LogTrace "WebLog.updateRedirectRules"
|
log.LogTrace "WebLog.updateRedirectRules"
|
||||||
match! findById webLog.Id with
|
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 -> ()
|
| None -> ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +61,14 @@ type PostgresWebLogData(log: ILogger) =
|
|||||||
let updateRssOptions (webLog: WebLog) = backgroundTask {
|
let updateRssOptions (webLog: WebLog) = backgroundTask {
|
||||||
log.LogTrace "WebLog.updateRssOptions"
|
log.LogTrace "WebLog.updateRssOptions"
|
||||||
match! findById webLog.Id with
|
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 -> ()
|
| None -> ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update settings for a web log
|
/// Update settings for a web log
|
||||||
let updateSettings (webLog: WebLog) =
|
let updateSettings (webLog: WebLog) =
|
||||||
log.LogTrace "WebLog.updateSettings"
|
log.LogTrace "WebLog.updateSettings"
|
||||||
Update.full Table.WebLog (string webLog.Id) webLog
|
Update.byId Table.WebLog webLog.Id webLog
|
||||||
|
|
||||||
interface IWebLogData with
|
interface IWebLogData with
|
||||||
member _.Add webLog = add webLog
|
member _.Add webLog = add webLog
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents
|
||||||
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
@ -24,13 +25,13 @@ type PostgresWebLogUserData(log: ILogger) =
|
|||||||
Custom.scalar
|
Custom.scalar
|
||||||
$" SELECT ( EXISTS (SELECT 1 FROM {Table.Page} WHERE {criteria})
|
$" SELECT ( EXISTS (SELECT 1 FROM {Table.Page} WHERE {criteria})
|
||||||
OR EXISTS (SELECT 1 FROM {Table.Post} WHERE {criteria})
|
OR EXISTS (SELECT 1 FROM {Table.Post} WHERE {criteria})
|
||||||
) AS {existsName}"
|
) AS it"
|
||||||
[ "@criteria", Query.jsonbDocParam {| AuthorId = userId |} ]
|
[ jsonParam "@criteria" {| AuthorId = userId |} ]
|
||||||
Map.toExists
|
toExists
|
||||||
if isAuthor then
|
if isAuthor then
|
||||||
return Error "User has pages or posts; cannot delete"
|
return Error "User has pages or posts; cannot delete"
|
||||||
else
|
else
|
||||||
do! Delete.byId Table.WebLogUser (string userId)
|
do! Delete.byId Table.WebLogUser userId
|
||||||
return Ok true
|
return Ok true
|
||||||
| None -> return Error "User does not exist"
|
| None -> return Error "User does not exist"
|
||||||
}
|
}
|
||||||
@ -67,8 +68,7 @@ type PostgresWebLogUserData(log: ILogger) =
|
|||||||
Configuration.dataSource ()
|
Configuration.dataSource ()
|
||||||
|> Sql.fromDataSource
|
|> Sql.fromDataSource
|
||||||
|> Sql.executeTransactionAsync
|
|> Sql.executeTransactionAsync
|
||||||
[ Query.insert Table.WebLogUser,
|
[ Query.insert Table.WebLogUser, users |> List.map (fun user -> [ jsonParam "@data" user ]) ]
|
||||||
users |> List.map (fun user -> Query.docParameters (string user.Id) user) ]
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ type PostgresWebLogUserData(log: ILogger) =
|
|||||||
let setLastSeen (userId: WebLogUserId) webLogId = backgroundTask {
|
let setLastSeen (userId: WebLogUserId) webLogId = backgroundTask {
|
||||||
log.LogTrace "WebLogUser.setLastSeen"
|
log.LogTrace "WebLogUser.setLastSeen"
|
||||||
match! Document.existsByWebLog Table.WebLogUser userId webLogId with
|
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 -> ()
|
| false -> ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
namespace MyWebLog.Data
|
namespace MyWebLog.Data
|
||||||
|
|
||||||
open BitBadger.Npgsql.Documents
|
open BitBadger.Documents
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data.Postgres
|
open MyWebLog.Data.Postgres
|
||||||
@ -31,8 +31,8 @@ type PostgresData(log: ILogger<PostgresData>, ser: JsonSerializer) =
|
|||||||
// Theme tables
|
// Theme tables
|
||||||
if needsTable Table.Theme then
|
if needsTable Table.Theme then
|
||||||
isNew <- true
|
isNew <- true
|
||||||
Definition.createTable Table.Theme
|
Query.Definition.ensureTable Table.Theme
|
||||||
Definition.createKey Table.Theme
|
Query.Definition.ensureKey Table.Theme
|
||||||
if needsTable Table.ThemeAsset then
|
if needsTable Table.ThemeAsset then
|
||||||
$"CREATE TABLE {Table.ThemeAsset} (
|
$"CREATE TABLE {Table.ThemeAsset} (
|
||||||
theme_id TEXT NOT NULL,
|
theme_id TEXT NOT NULL,
|
||||||
@ -43,30 +43,29 @@ type PostgresData(log: ILogger<PostgresData>, ser: JsonSerializer) =
|
|||||||
|
|
||||||
// Web log table
|
// Web log table
|
||||||
if needsTable Table.WebLog then
|
if needsTable Table.WebLog then
|
||||||
Definition.createTable Table.WebLog
|
Query.Definition.ensureTable Table.WebLog
|
||||||
Definition.createKey Table.WebLog
|
Query.Definition.ensureKey Table.WebLog
|
||||||
Definition.createIndex Table.WebLog Optimized
|
Query.Definition.ensureDocumentIndex Table.WebLog Optimized
|
||||||
|
|
||||||
// Category table
|
// Category table
|
||||||
if needsTable Table.Category then
|
if needsTable Table.Category then
|
||||||
Definition.createTable Table.Category
|
Query.Definition.ensureTable Table.Category
|
||||||
Definition.createKey Table.Category
|
Query.Definition.ensureKey Table.Category
|
||||||
Definition.createIndex Table.Category Optimized
|
Query.Definition.ensureDocumentIndex Table.Category Optimized
|
||||||
|
|
||||||
// Web log user table
|
// Web log user table
|
||||||
if needsTable Table.WebLogUser then
|
if needsTable Table.WebLogUser then
|
||||||
Definition.createTable Table.WebLogUser
|
Query.Definition.ensureTable Table.WebLogUser
|
||||||
Definition.createKey Table.WebLogUser
|
Query.Definition.ensureKey Table.WebLogUser
|
||||||
Definition.createIndex Table.WebLogUser Optimized
|
Query.Definition.ensureDocumentIndex Table.WebLogUser Optimized
|
||||||
|
|
||||||
// Page tables
|
// Page tables
|
||||||
if needsTable Table.Page then
|
if needsTable Table.Page then
|
||||||
Definition.createTable Table.Page
|
Query.Definition.ensureTable Table.Page
|
||||||
Definition.createKey Table.Page
|
Query.Definition.ensureKey Table.Page
|
||||||
$"CREATE INDEX page_web_log_idx ON {Table.Page} ((data ->> '{nameof Page.Empty.WebLogId}'))"
|
Query.Definition.ensureIndexOn Table.Page "author" [ nameof Page.Empty.AuthorId ]
|
||||||
$"CREATE INDEX page_author_idx ON {Table.Page} ((data ->> '{nameof Page.Empty.AuthorId}'))"
|
Query.Definition.ensureIndexOn
|
||||||
$"CREATE INDEX page_permalink_idx ON {Table.Page}
|
Table.Page "permalink" [ nameof Page.Empty.WebLogId; nameof Page.Empty.Permalink ]
|
||||||
((data ->> '{nameof Page.Empty.WebLogId}'), (data ->> '{nameof Page.Empty.Permalink}'))"
|
|
||||||
if needsTable Table.PageRevision then
|
if needsTable Table.PageRevision then
|
||||||
$"CREATE TABLE {Table.PageRevision} (
|
$"CREATE TABLE {Table.PageRevision} (
|
||||||
page_id TEXT NOT NULL,
|
page_id TEXT NOT NULL,
|
||||||
@ -76,15 +75,15 @@ type PostgresData(log: ILogger<PostgresData>, ser: JsonSerializer) =
|
|||||||
|
|
||||||
// Post tables
|
// Post tables
|
||||||
if needsTable Table.Post then
|
if needsTable Table.Post then
|
||||||
Definition.createTable Table.Post
|
Query.Definition.ensureTable Table.Post
|
||||||
Definition.createKey Table.Post
|
Query.Definition.ensureKey Table.Post
|
||||||
$"CREATE INDEX post_web_log_idx ON {Table.Post} ((data ->> '{nameof Post.Empty.WebLogId}'))"
|
Query.Definition.ensureIndexOn Table.Post "author" [ nameof Post.Empty.AuthorId ]
|
||||||
$"CREATE INDEX post_author_idx ON {Table.Post} ((data ->> '{nameof Post.Empty.AuthorId}'))"
|
Query.Definition.ensureIndexOn
|
||||||
$"CREATE INDEX post_status_idx ON {Table.Post}
|
Table.Post "permalink" [ nameof Post.Empty.WebLogId; nameof Post.Empty.Permalink ]
|
||||||
((data ->> '{nameof Post.Empty.WebLogId}'), (data ->> '{nameof Post.Empty.Status}'),
|
Query.Definition.ensureIndexOn
|
||||||
(data ->> '{nameof Post.Empty.UpdatedOn}'))"
|
Table.Post
|
||||||
$"CREATE INDEX post_permalink_idx ON {Table.Post}
|
"status"
|
||||||
((data ->> '{nameof Post.Empty.WebLogId}'), (data ->> '{nameof Post.Empty.Permalink}'))"
|
[ 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_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}']))"
|
$"CREATE INDEX post_tag_idx ON {Table.Post} USING GIN ((data['{nameof Post.Empty.Tags}']))"
|
||||||
if needsTable Table.PostRevision then
|
if needsTable Table.PostRevision then
|
||||||
@ -94,16 +93,15 @@ type PostgresData(log: ILogger<PostgresData>, ser: JsonSerializer) =
|
|||||||
revision_text TEXT NOT NULL,
|
revision_text TEXT NOT NULL,
|
||||||
PRIMARY KEY (post_id, as_of))"
|
PRIMARY KEY (post_id, as_of))"
|
||||||
if needsTable Table.PostComment then
|
if needsTable Table.PostComment then
|
||||||
Definition.createTable Table.PostComment
|
Query.Definition.ensureTable Table.PostComment
|
||||||
Definition.createKey Table.PostComment
|
Query.Definition.ensureKey Table.PostComment
|
||||||
$"CREATE INDEX post_comment_post_idx ON {Table.PostComment}
|
Query.Definition.ensureIndexOn Table.PostComment "post" [ nameof Comment.Empty.PostId ]
|
||||||
((data ->> '{nameof Comment.Empty.PostId}'))"
|
|
||||||
|
|
||||||
// Tag map table
|
// Tag map table
|
||||||
if needsTable Table.TagMap then
|
if needsTable Table.TagMap then
|
||||||
Definition.createTable Table.TagMap
|
Query.Definition.ensureTable Table.TagMap
|
||||||
Definition.createKey Table.TagMap
|
Query.Definition.ensureKey Table.TagMap
|
||||||
Definition.createIndex Table.TagMap Optimized
|
Query.Definition.ensureDocumentIndex Table.TagMap Optimized
|
||||||
|
|
||||||
// Uploaded file table
|
// Uploaded file table
|
||||||
if needsTable Table.Upload then
|
if needsTable Table.Upload then
|
||||||
|
@ -50,14 +50,12 @@ type RedirectRuleMiddleware(next: RequestDelegate, log: ILogger<RedirectRuleMidd
|
|||||||
|
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
open BitBadger.Documents
|
||||||
open Microsoft.Extensions.DependencyInjection
|
open Microsoft.Extensions.DependencyInjection
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
open Newtonsoft.Json
|
open Newtonsoft.Json
|
||||||
open Npgsql
|
open Npgsql
|
||||||
|
|
||||||
// The PostgreSQL document library
|
|
||||||
module Postgres = BitBadger.Npgsql.FSharp.Documents
|
|
||||||
|
|
||||||
// The SQLite document library
|
// The SQLite document library
|
||||||
module Sqlite = BitBadger.Sqlite.FSharp.Documents
|
module Sqlite = BitBadger.Sqlite.FSharp.Documents
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user