Update for doc lib v4-rc4

This commit is contained in:
2024-09-17 08:05:30 -04:00
parent 95be82cc84
commit 0032d15c0a
16 changed files with 119 additions and 188 deletions

View File

@@ -20,37 +20,41 @@ type PostgresCategoryData(log: ILogger) =
log.LogTrace "Category.countTopLevel"
Custom.scalar
$"""{Query.byContains (Query.count Table.Category)}
AND {Query.whereByFields Any [ Field.NEX (nameof Category.Empty.ParentId) ]}"""
AND {Query.whereByFields Any [ Field.NotExists (nameof Category.Empty.ParentId) ]}"""
[ webLogContains webLogId ]
toCount
/// Find all categories for the given web log
let findByWebLog webLogId =
log.LogTrace "Category.findByWebLog"
Find.byContains<Category> Table.Category (webLogDoc webLogId)
/// Retrieve all categories for the given web log in a DotLiquid-friendly format
let findAllForView webLogId = backgroundTask {
log.LogTrace "Category.findAllForView"
let! cats =
Custom.list
$"{selectWithCriteria Table.Category} ORDER BY LOWER(data->>'{nameof Category.Empty.Name}')"
[ webLogContains webLogId ]
fromData<Category>
let ordered = Utils.orderByHierarchy cats None None []
let counts =
let! cats = findByWebLog webLogId
let ordered = Utils.orderByHierarchy (cats |> List.sortBy _.Name.ToLowerInvariant()) None None []
let counts =
ordered
|> Seq.map (fun it ->
// Parent category post counts include posts in subcategories
let catIdSql, catIdParams =
let catIdField =
ordered
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|> Seq.map _.Id
|> Seq.append (Seq.singleton it.Id)
|> List.ofSeq
|> arrayContains (nameof Post.Empty.CategoryIds) id
|> Seq.map box
|> Field.InArray (nameof Post.Empty.CategoryIds) Table.Post
let query =
(Query.statementWhere
(Query.count Table.Post)
$"""{Query.whereDataContains "@criteria"} AND {Query.whereByFields All [ catIdField ]}""")
.Replace("(*)", $"(DISTINCT data->>'{nameof Post.Empty.Id}')")
let postCount =
Custom.scalar
$"""SELECT COUNT(DISTINCT data->>'{nameof Post.Empty.Id}') AS it
FROM {Table.Post}
WHERE {Query.whereDataContains "@criteria"}
AND {catIdSql}"""
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catIdParams ]
query
(addFieldParams
[ catIdField ] [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ])
toCount
|> Async.AwaitTask
|> Async.RunSynchronously
@@ -71,11 +75,6 @@ type PostgresCategoryData(log: ILogger) =
log.LogTrace "Category.findById"
Document.findByIdAndWebLog<CategoryId, Category> Table.Category catId webLogId
/// Find all categories for the given web log
let findByWebLog webLogId =
log.LogTrace "Category.findByWebLog"
Find.byContains<Category> Table.Category (webLogDoc webLogId)
/// Delete a category
let delete catId webLogId = backgroundTask {
log.LogTrace "Category.delete"

View File

@@ -85,27 +85,6 @@ let webLogContains webLogId =
let selectWithCriteria tableName =
Query.byContains (Query.find tableName)
/// Create the SQL and parameters for an IN clause
let inClause<'T> colNameAndPrefix paramName (items: 'T list) =
if List.isEmpty items then "", []
else
let mutable idx = 0
items
|> List.skip 1
|> List.fold (fun (itemS, itemP) it ->
idx <- idx + 1
$"{itemS}, @%s{paramName}{idx}", ($"@%s{paramName}{idx}", Sql.string (string it)) :: itemP)
(Seq.ofList items
|> Seq.map (fun it ->
$"%s{colNameAndPrefix} IN (@%s{paramName}0", [ $"@%s{paramName}0", Sql.string (string it) ])
|> Seq.head)
|> function sql, ps -> $"{sql})", ps
/// Create the SQL and parameters for match-any array query
let arrayContains<'T> name (valueFunc: 'T -> string) (items: 'T list) =
$"data['{name}'] ?| @{name}Values",
($"@{name}Values", Sql.stringArray (items |> List.map valueFunc |> Array.ofList))
/// Get the first result of the given query
let tryHead<'T> (query: Task<'T list>) = backgroundTask {
let! results = query

View File

@@ -111,15 +111,14 @@ type PostgresPageData(log: ILogger) =
log.LogTrace "Page.findCurrentPermalink"
if List.isEmpty permalinks then return None
else
let linkSql, linkParam = arrayContains (nameof Page.Empty.PriorPermalinks) string permalinks
return!
Custom.single
$"""SELECT data->>'{nameof Page.Empty.Permalink}' AS permalink
FROM page
WHERE {Query.whereDataContains "@criteria"}
AND {linkSql}"""
[ webLogContains webLogId; linkParam ]
Map.toPermalink
let linkField =
Field.InArray (nameof Page.Empty.PriorPermalinks) Table.Page (List.map (string >> box) permalinks)
let query =
(Query.statementWhere
(Query.find Table.Page)
$"""{Query.whereDataContains "@criteria"} AND {Query.whereByFields All [ linkField ]}""")
.Replace("SELECT data", $"SELECT data->>'{nameof Page.Empty.Permalink}' AS permalink")
return! Custom.single query (addFieldParams [ linkField ] [ webLogContains webLogId ]) Map.toPermalink
}
/// Get all complete pages for the given web log

View File

@@ -97,15 +97,14 @@ type PostgresPostData(log: ILogger) =
log.LogTrace "Post.findCurrentPermalink"
if List.isEmpty permalinks then return None
else
let linkSql, linkParam = arrayContains (nameof Post.Empty.PriorPermalinks) string permalinks
return!
Custom.single
$"""SELECT data->>'{nameof Post.Empty.Permalink}' AS permalink
FROM {Table.Post}
WHERE {Query.whereDataContains "@criteria"}
AND {linkSql}"""
[ webLogContains webLogId; linkParam ]
Map.toPermalink
let linkField =
Field.InArray (nameof Post.Empty.PriorPermalinks) Table.Post (List.map (string >> box) permalinks)
let query =
(Query.statementWhere
(Query.find Table.Post)
$"""{Query.whereDataContains "@criteria"} AND {Query.whereByFields All [ linkField ]}""")
.Replace("SELECT data", $"SELECT data->>'{nameof Post.Empty.Permalink}' AS permalink")
return! Custom.single query (addFieldParams [ linkField ] [ webLogContains webLogId ]) Map.toPermalink
}
/// Get all complete posts for the given web log
@@ -122,13 +121,13 @@ type PostgresPostData(log: ILogger) =
/// Get a page of categorized posts for the given web log (excludes revisions)
let findPageOfCategorizedPosts webLogId (categoryIds: CategoryId list) pageNbr postsPerPage =
log.LogTrace "Post.findPageOfCategorizedPosts"
let catSql, catParam = arrayContains (nameof Post.Empty.CategoryIds) string categoryIds
let catIdField = Field.InArray (nameof Post.Empty.CategoryIds) Table.Post (List.map (string >> box) categoryIds)
Custom.list
$"""{selectWithCriteria Table.Post}
AND {catSql}
AND {Query.whereByFields All [ catIdField ]}
{Query.orderBy [ Field.Named $"{nameof Post.Empty.PublishedOn} DESC" ] PostgreSQL}
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catParam ]
(addFieldParams [ catIdField] [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ])
postWithoutLinks
/// Get a page of posts for the given web log (excludes text and revisions)

View File

@@ -6,6 +6,7 @@ open Microsoft.Extensions.Logging
open MyWebLog
open MyWebLog.Data
open Npgsql.FSharp
open Npgsql.Internal.Postgres
/// PostgreSQL myWebLog tag mapping data implementation
type PostgresTagMapData(log: ILogger) =
@@ -36,12 +37,12 @@ type PostgresTagMapData(log: ILogger) =
Find.byContainsOrdered<TagMap> Table.TagMap (webLogDoc webLogId) [ Field.Named (nameof TagMap.Empty.Tag) ]
/// Find any tag mappings in a list of tags for the given web log
let findMappingForTags tags webLogId =
let findMappingForTags (tags: string list) webLogId =
log.LogTrace "TagMap.findMappingForTags"
let tagSql, tagParam = arrayContains (nameof TagMap.Empty.Tag) id tags
let tagField = Field.InArray (nameof TagMap.Empty.Tag) Table.TagMap (List.map box tags)
Custom.list
$"{selectWithCriteria Table.TagMap} AND {tagSql}"
[ webLogContains webLogId; tagParam ]
$"{selectWithCriteria Table.TagMap} AND {Query.whereByFields All [ tagField ]}"
(addFieldParams [ tagField ] [ webLogContains webLogId ])
fromData<TagMap>
/// Save a tag mapping

View File

@@ -17,7 +17,7 @@ type PostgresThemeData(log: ILogger) =
/// Retrieve all themes (except 'admin'; excludes template text)
let all () =
log.LogTrace "Theme.all"
let fields = [ Field.NE (nameof Theme.Empty.Id) "admin" ]
let fields = [ Field.NotEqual (nameof Theme.Empty.Id) "admin" ]
Custom.list
(Query.byFields (Query.find Table.Theme) Any fields
+ Query.orderBy [ Field.Named (nameof Theme.Empty.Id) ] PostgreSQL)

View File

@@ -55,11 +55,11 @@ type PostgresWebLogUserData(log: ILogger) =
/// Find the names of users by their IDs for the given web log
let findNames webLogId (userIds: WebLogUserId list) = backgroundTask {
log.LogTrace "WebLogUser.findNames"
let idSql, idParams = inClause $"AND data->>'{nameof WebLogUser.Empty.Id}'" "id" userIds
let idField = Field.In (nameof WebLogUser.Empty.Id) (List.map (string >> box) userIds)
let! users =
Custom.list
$"{selectWithCriteria Table.WebLogUser} {idSql}"
(webLogContains webLogId :: idParams)
$"{selectWithCriteria Table.WebLogUser} AND {Query.whereByFields All [ idField ]}"
(addFieldParams [ idField ] [ webLogContains webLogId ])
fromData<WebLogUser>
return users |> List.map (fun u -> { Name = string u.Id; Value = u.DisplayName })
}