Update for doc lib v4-rc4
This commit is contained in:
parent
95be82cc84
commit
0032d15c0a
@ -5,14 +5,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BitBadger.Documents.Postgres" Version="4.0.0-rc3" />
|
<PackageReference Include="BitBadger.Documents.Postgres" Version="4.0.0-rc4" />
|
||||||
<PackageReference Include="BitBadger.Documents.Sqlite" Version="4.0.0-rc3" />
|
<PackageReference Include="BitBadger.Documents.Sqlite" Version="4.0.0-rc4" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.8" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.8" />
|
||||||
<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" />
|
||||||
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
||||||
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.1.0" />
|
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.1.0" />
|
||||||
<PackageReference Include="Npgsql.NodaTime" Version="8.0.3" />
|
<PackageReference Include="Npgsql.NodaTime" Version="8.0.4" />
|
||||||
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
||||||
<PackageReference Include="RethinkDb.Driver.FSharp" Version="0.9.0-beta-07" />
|
<PackageReference Include="RethinkDb.Driver.FSharp" Version="0.9.0-beta-07" />
|
||||||
<PackageReference Update="FSharp.Core" Version="8.0.400" />
|
<PackageReference Update="FSharp.Core" Version="8.0.400" />
|
||||||
|
@ -20,37 +20,41 @@ type PostgresCategoryData(log: ILogger) =
|
|||||||
log.LogTrace "Category.countTopLevel"
|
log.LogTrace "Category.countTopLevel"
|
||||||
Custom.scalar
|
Custom.scalar
|
||||||
$"""{Query.byContains (Query.count Table.Category)}
|
$"""{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 ]
|
[ webLogContains webLogId ]
|
||||||
toCount
|
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
|
/// Retrieve all categories for the given web log in a DotLiquid-friendly format
|
||||||
let findAllForView webLogId = backgroundTask {
|
let findAllForView webLogId = backgroundTask {
|
||||||
log.LogTrace "Category.findAllForView"
|
log.LogTrace "Category.findAllForView"
|
||||||
let! cats =
|
let! cats = findByWebLog webLogId
|
||||||
Custom.list
|
let ordered = Utils.orderByHierarchy (cats |> List.sortBy _.Name.ToLowerInvariant()) None None []
|
||||||
$"{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 counts =
|
||||||
ordered
|
ordered
|
||||||
|> Seq.map (fun it ->
|
|> Seq.map (fun it ->
|
||||||
// Parent category post counts include posts in subcategories
|
// Parent category post counts include posts in subcategories
|
||||||
let catIdSql, catIdParams =
|
let catIdField =
|
||||||
ordered
|
ordered
|
||||||
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|
||||||
|> Seq.map _.Id
|
|> Seq.map _.Id
|
||||||
|> Seq.append (Seq.singleton it.Id)
|
|> Seq.append (Seq.singleton it.Id)
|
||||||
|> List.ofSeq
|
|> Seq.map box
|
||||||
|> arrayContains (nameof Post.Empty.CategoryIds) id
|
|> 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 =
|
let postCount =
|
||||||
Custom.scalar
|
Custom.scalar
|
||||||
$"""SELECT COUNT(DISTINCT data->>'{nameof Post.Empty.Id}') AS it
|
query
|
||||||
FROM {Table.Post}
|
(addFieldParams
|
||||||
WHERE {Query.whereDataContains "@criteria"}
|
[ catIdField ] [ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ])
|
||||||
AND {catIdSql}"""
|
|
||||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catIdParams ]
|
|
||||||
toCount
|
toCount
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.RunSynchronously
|
|> Async.RunSynchronously
|
||||||
@ -71,11 +75,6 @@ type PostgresCategoryData(log: ILogger) =
|
|||||||
log.LogTrace "Category.findById"
|
log.LogTrace "Category.findById"
|
||||||
Document.findByIdAndWebLog<CategoryId, Category> Table.Category catId webLogId
|
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
|
/// Delete a category
|
||||||
let delete catId webLogId = backgroundTask {
|
let delete catId webLogId = backgroundTask {
|
||||||
log.LogTrace "Category.delete"
|
log.LogTrace "Category.delete"
|
||||||
|
@ -85,27 +85,6 @@ let webLogContains webLogId =
|
|||||||
let selectWithCriteria tableName =
|
let selectWithCriteria tableName =
|
||||||
Query.byContains (Query.find 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
|
/// Get the first result of the given query
|
||||||
let tryHead<'T> (query: Task<'T list>) = backgroundTask {
|
let tryHead<'T> (query: Task<'T list>) = backgroundTask {
|
||||||
let! results = query
|
let! results = query
|
||||||
|
@ -111,15 +111,14 @@ type PostgresPageData(log: ILogger) =
|
|||||||
log.LogTrace "Page.findCurrentPermalink"
|
log.LogTrace "Page.findCurrentPermalink"
|
||||||
if List.isEmpty permalinks then return None
|
if List.isEmpty permalinks then return None
|
||||||
else
|
else
|
||||||
let linkSql, linkParam = arrayContains (nameof Page.Empty.PriorPermalinks) string permalinks
|
let linkField =
|
||||||
return!
|
Field.InArray (nameof Page.Empty.PriorPermalinks) Table.Page (List.map (string >> box) permalinks)
|
||||||
Custom.single
|
let query =
|
||||||
$"""SELECT data->>'{nameof Page.Empty.Permalink}' AS permalink
|
(Query.statementWhere
|
||||||
FROM page
|
(Query.find Table.Page)
|
||||||
WHERE {Query.whereDataContains "@criteria"}
|
$"""{Query.whereDataContains "@criteria"} AND {Query.whereByFields All [ linkField ]}""")
|
||||||
AND {linkSql}"""
|
.Replace("SELECT data", $"SELECT data->>'{nameof Page.Empty.Permalink}' AS permalink")
|
||||||
[ webLogContains webLogId; linkParam ]
|
return! Custom.single query (addFieldParams [ linkField ] [ webLogContains webLogId ]) Map.toPermalink
|
||||||
Map.toPermalink
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all complete pages for the given web log
|
/// Get all complete pages for the given web log
|
||||||
|
@ -97,15 +97,14 @@ type PostgresPostData(log: ILogger) =
|
|||||||
log.LogTrace "Post.findCurrentPermalink"
|
log.LogTrace "Post.findCurrentPermalink"
|
||||||
if List.isEmpty permalinks then return None
|
if List.isEmpty permalinks then return None
|
||||||
else
|
else
|
||||||
let linkSql, linkParam = arrayContains (nameof Post.Empty.PriorPermalinks) string permalinks
|
let linkField =
|
||||||
return!
|
Field.InArray (nameof Post.Empty.PriorPermalinks) Table.Post (List.map (string >> box) permalinks)
|
||||||
Custom.single
|
let query =
|
||||||
$"""SELECT data->>'{nameof Post.Empty.Permalink}' AS permalink
|
(Query.statementWhere
|
||||||
FROM {Table.Post}
|
(Query.find Table.Post)
|
||||||
WHERE {Query.whereDataContains "@criteria"}
|
$"""{Query.whereDataContains "@criteria"} AND {Query.whereByFields All [ linkField ]}""")
|
||||||
AND {linkSql}"""
|
.Replace("SELECT data", $"SELECT data->>'{nameof Post.Empty.Permalink}' AS permalink")
|
||||||
[ webLogContains webLogId; linkParam ]
|
return! Custom.single query (addFieldParams [ linkField ] [ webLogContains webLogId ]) Map.toPermalink
|
||||||
Map.toPermalink
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all complete posts for the given web log
|
/// 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)
|
/// Get a page of categorized posts for the given web log (excludes revisions)
|
||||||
let findPageOfCategorizedPosts webLogId (categoryIds: CategoryId list) pageNbr postsPerPage =
|
let findPageOfCategorizedPosts webLogId (categoryIds: CategoryId list) pageNbr postsPerPage =
|
||||||
log.LogTrace "Post.findPageOfCategorizedPosts"
|
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
|
Custom.list
|
||||||
$"""{selectWithCriteria Table.Post}
|
$"""{selectWithCriteria Table.Post}
|
||||||
AND {catSql}
|
AND {Query.whereByFields All [ catIdField ]}
|
||||||
{Query.orderBy [ Field.Named $"{nameof Post.Empty.PublishedOn} DESC" ] PostgreSQL}
|
{Query.orderBy [ Field.Named $"{nameof Post.Empty.PublishedOn} DESC" ] PostgreSQL}
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
|
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
|
postWithoutLinks
|
||||||
|
|
||||||
/// 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)
|
||||||
|
@ -6,6 +6,7 @@ open Microsoft.Extensions.Logging
|
|||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
open Npgsql.Internal.Postgres
|
||||||
|
|
||||||
/// PostgreSQL myWebLog tag mapping data implementation
|
/// PostgreSQL myWebLog tag mapping data implementation
|
||||||
type PostgresTagMapData(log: ILogger) =
|
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.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
|
/// 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"
|
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
|
Custom.list
|
||||||
$"{selectWithCriteria Table.TagMap} AND {tagSql}"
|
$"{selectWithCriteria Table.TagMap} AND {Query.whereByFields All [ tagField ]}"
|
||||||
[ webLogContains webLogId; tagParam ]
|
(addFieldParams [ tagField ] [ webLogContains webLogId ])
|
||||||
fromData<TagMap>
|
fromData<TagMap>
|
||||||
|
|
||||||
/// Save a tag mapping
|
/// Save a tag mapping
|
||||||
|
@ -17,7 +17,7 @@ type PostgresThemeData(log: ILogger) =
|
|||||||
/// Retrieve all themes (except 'admin'; excludes template text)
|
/// Retrieve all themes (except 'admin'; excludes template text)
|
||||||
let all () =
|
let all () =
|
||||||
log.LogTrace "Theme.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
|
Custom.list
|
||||||
(Query.byFields (Query.find Table.Theme) Any fields
|
(Query.byFields (Query.find Table.Theme) Any fields
|
||||||
+ Query.orderBy [ Field.Named (nameof Theme.Empty.Id) ] PostgreSQL)
|
+ Query.orderBy [ Field.Named (nameof Theme.Empty.Id) ] PostgreSQL)
|
||||||
|
@ -55,11 +55,11 @@ type PostgresWebLogUserData(log: ILogger) =
|
|||||||
/// Find the names of users by their IDs for the given web log
|
/// Find the names of users by their IDs for the given web log
|
||||||
let findNames webLogId (userIds: WebLogUserId list) = backgroundTask {
|
let findNames webLogId (userIds: WebLogUserId list) = backgroundTask {
|
||||||
log.LogTrace "WebLogUser.findNames"
|
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 =
|
let! users =
|
||||||
Custom.list
|
Custom.list
|
||||||
$"{selectWithCriteria Table.WebLogUser} {idSql}"
|
$"{selectWithCriteria Table.WebLogUser} AND {Query.whereByFields All [ idField ]}"
|
||||||
(webLogContains webLogId :: idParams)
|
(addFieldParams [ idField ] [ webLogContains webLogId ])
|
||||||
fromData<WebLogUser>
|
fromData<WebLogUser>
|
||||||
return users |> List.map (fun u -> { Name = string u.Id; Value = u.DisplayName })
|
return users |> List.map (fun u -> { Name = string u.Id; Value = u.DisplayName })
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ type SQLiteCategoryData(conn: SqliteConnection, ser: JsonSerializer, log: ILogge
|
|||||||
/// Count all top-level categories for the given web log
|
/// Count all top-level categories for the given web log
|
||||||
let countTopLevel webLogId = backgroundTask {
|
let countTopLevel webLogId = backgroundTask {
|
||||||
log.LogTrace "Category.countTopLevel"
|
log.LogTrace "Category.countTopLevel"
|
||||||
let! count = conn.countByFields Table.Category All [ webLogField webLogId; Field.NEX parentIdField ]
|
let! count = conn.countByFields Table.Category All [ webLogField webLogId; Field.NotExists parentIdField ]
|
||||||
return int count
|
return int count
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,20 +43,20 @@ type SQLiteCategoryData(conn: SqliteConnection, ser: JsonSerializer, log: ILogge
|
|||||||
ordered
|
ordered
|
||||||
|> Seq.map (fun it -> backgroundTask {
|
|> Seq.map (fun it -> backgroundTask {
|
||||||
// Parent category post counts include posts in subcategories
|
// Parent category post counts include posts in subcategories
|
||||||
let catSql, catParams =
|
let childCats =
|
||||||
ordered
|
ordered
|
||||||
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|
||||||
|> Seq.map _.Id
|
|> Seq.map _.Id
|
||||||
|> Seq.append (Seq.singleton it.Id)
|
|> Seq.append (Seq.singleton it.Id)
|
||||||
|> List.ofSeq
|
|> Seq.map box
|
||||||
|> inJsonArray Table.Post (nameof Post.Empty.CategoryIds) "catId"
|
let fields =
|
||||||
let query = $"""
|
[ webLogField webLogId
|
||||||
SELECT COUNT(DISTINCT data->>'{nameof Post.Empty.Id}')
|
Field.Equal (nameof Post.Empty.Status) (string Published)
|
||||||
FROM {Table.Post}
|
Field.InArray (nameof Post.Empty.CategoryIds) Table.Post childCats ]
|
||||||
WHERE {Document.Query.whereByWebLog}
|
let query =
|
||||||
AND data->>'{nameof Post.Empty.Status}' = '{string Published}'
|
(Query.statementWhere (Query.count Table.Post) (Query.whereByFields All fields))
|
||||||
AND {catSql}"""
|
.Replace("(*)", $"(DISTINCT data->>'{nameof Post.Empty.Id}')")
|
||||||
let! postCount = conn.customScalar query (webLogParam webLogId :: catParams) toCount
|
let! postCount = conn.customScalar query (addFieldParams fields []) toCount
|
||||||
return it.Id, int postCount
|
return it.Id, int postCount
|
||||||
})
|
})
|
||||||
|> Task.WhenAll
|
|> Task.WhenAll
|
||||||
@ -80,24 +80,22 @@ type SQLiteCategoryData(conn: SqliteConnection, ser: JsonSerializer, log: ILogge
|
|||||||
match! findById catId webLogId with
|
match! findById catId webLogId with
|
||||||
| Some cat ->
|
| Some cat ->
|
||||||
// Reassign any children to the category's parent category
|
// Reassign any children to the category's parent category
|
||||||
let! children = conn.countByFields Table.Category Any [ Field.EQ parentIdField (string catId) ]
|
let! children = conn.countByFields Table.Category Any [ Field.Equal parentIdField (string catId) ]
|
||||||
if children > 0L then
|
if children > 0L then
|
||||||
let parent = [ Field.EQ parentIdField (string catId) ]
|
let parent = [ Field.Equal parentIdField (string catId) ]
|
||||||
match cat.ParentId with
|
match cat.ParentId with
|
||||||
| Some _ -> do! conn.patchByFields Table.Category Any parent {| ParentId = cat.ParentId |}
|
| Some _ -> do! conn.patchByFields Table.Category Any parent {| ParentId = cat.ParentId |}
|
||||||
| None -> do! conn.removeFieldsByFields Table.Category Any parent [ parentIdField ]
|
| None -> do! conn.removeFieldsByFields Table.Category Any parent [ parentIdField ]
|
||||||
// Delete the category off all posts where it is assigned, and the category itself
|
// Delete the category off all posts where it is assigned, and the category itself
|
||||||
let catIdField = nameof Post.Empty.CategoryIds
|
let catIdField = nameof Post.Empty.CategoryIds
|
||||||
|
let fields = [ webLogField webLogId; Field.InArray catIdField Table.Post [ string catId ] ]
|
||||||
|
let query =
|
||||||
|
(Query.statementWhere (Query.find Table.Post) (Query.whereByFields All fields))
|
||||||
|
.Replace("SELECT data", $"SELECT data->>'{nameof Post.Empty.Id}', data->'{catIdField}'")
|
||||||
let! posts =
|
let! posts =
|
||||||
conn.customList
|
conn.customList
|
||||||
$"SELECT data->>'{nameof Post.Empty.Id}', data->'{catIdField}'
|
query
|
||||||
FROM {Table.Post}
|
(addFieldParams fields [])
|
||||||
WHERE {Document.Query.whereByWebLog}
|
|
||||||
AND EXISTS
|
|
||||||
(SELECT 1
|
|
||||||
FROM json_each({Table.Post}.data->'{catIdField}')
|
|
||||||
WHERE json_each.value = @id)"
|
|
||||||
[ idParam catId; webLogParam webLogId ]
|
|
||||||
(fun rdr -> rdr.GetString 0, Utils.deserialize<string list> ser (rdr.GetString 1))
|
(fun rdr -> rdr.GetString 0, Utils.deserialize<string list> ser (rdr.GetString 1))
|
||||||
for postId, cats in posts do
|
for postId, cats in posts do
|
||||||
do! conn.patchById
|
do! conn.patchById
|
||||||
|
@ -82,39 +82,6 @@ let instantParam =
|
|||||||
let maybeInstant =
|
let maybeInstant =
|
||||||
Option.map instantParam >> maybe
|
Option.map instantParam >> maybe
|
||||||
|
|
||||||
/// Create the SQL and parameters for an EXISTS applied to a JSON array
|
|
||||||
let inJsonArray<'T> table jsonField 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}", (SqliteParameter($"@%s{paramName}{idx}", string it) :: itemP))
|
|
||||||
(Seq.ofList items
|
|
||||||
|> Seq.map (fun it -> $"(@%s{paramName}0", [ SqliteParameter($"@%s{paramName}0", string it) ])
|
|
||||||
|> Seq.head)
|
|
||||||
|> function
|
|
||||||
sql, ps ->
|
|
||||||
$"EXISTS (SELECT 1 FROM json_each(%s{table}.data, '$.%s{jsonField}') WHERE value IN {sql}))", ps
|
|
||||||
|
|
||||||
/// Create the SQL and parameters for an IN clause
|
|
||||||
let inClause<'T> colNameAndPrefix paramName (valueFunc: 'T -> string) (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}", (SqliteParameter ($"@%s{paramName}{idx}", valueFunc it) :: itemP))
|
|
||||||
(Seq.ofList items
|
|
||||||
|> Seq.map (fun it ->
|
|
||||||
$"%s{colNameAndPrefix} IN (@%s{paramName}0", [ SqliteParameter ($"@%s{paramName}0", valueFunc it) ])
|
|
||||||
|> Seq.head)
|
|
||||||
|> function sql, ps -> $"{sql})", ps
|
|
||||||
|
|
||||||
|
|
||||||
/// Functions to map domain items from a data reader
|
/// Functions to map domain items from a data reader
|
||||||
module Map =
|
module Map =
|
||||||
@ -219,8 +186,6 @@ module Map =
|
|||||||
|
|
||||||
|
|
||||||
open BitBadger.Documents
|
open BitBadger.Documents
|
||||||
open BitBadger.Documents.Sqlite
|
|
||||||
open BitBadger.Documents.Sqlite.WithConn
|
|
||||||
|
|
||||||
/// Create a named parameter
|
/// Create a named parameter
|
||||||
let sqlParam name (value: obj) =
|
let sqlParam name (value: obj) =
|
||||||
@ -232,26 +197,15 @@ let webLogParam (webLogId: WebLogId) =
|
|||||||
|
|
||||||
/// Create a field for an ID value
|
/// Create a field for an ID value
|
||||||
let idField<'T> (idValue: 'T) =
|
let idField<'T> (idValue: 'T) =
|
||||||
{ Field.EQ "Id" (string idValue) with ParameterName = Some "@id" }
|
{ Field.Equal "Id" (string idValue) with ParameterName = Some "@id" }
|
||||||
|
|
||||||
/// Create a web log field
|
/// Create a web log field
|
||||||
let webLogField (webLogId: WebLogId) =
|
let webLogField (webLogId: WebLogId) =
|
||||||
{ Field.EQ "WebLogId" (string webLogId) with ParameterName = Some "@webLogId" }
|
{ Field.Equal "WebLogId" (string webLogId) with ParameterName = Some "@webLogId" }
|
||||||
|
|
||||||
/// Functions for manipulating documents
|
|
||||||
module Document =
|
|
||||||
|
|
||||||
/// Queries to assist with document manipulation
|
|
||||||
module Query =
|
|
||||||
|
|
||||||
/// Fragment to add a web log ID condition to a WHERE clause (parameter @webLogId)
|
|
||||||
let whereByWebLog =
|
|
||||||
Query.whereByFields Any [ { Field.EQ "WebLogId" "" with ParameterName = Some "@webLogId" } ]
|
|
||||||
|
|
||||||
/// A query to select from a table by its web log ID
|
|
||||||
let selectByWebLog table =
|
|
||||||
Query.statementWhere (Query.find table) whereByWebLog
|
|
||||||
|
|
||||||
|
open BitBadger.Documents.Sqlite
|
||||||
|
open BitBadger.Documents.Sqlite.WithConn
|
||||||
|
|
||||||
/// Functions to support revisions
|
/// Functions to support revisions
|
||||||
module Revisions =
|
module Revisions =
|
||||||
@ -270,7 +224,7 @@ module Revisions =
|
|||||||
$"SELECT pr.*
|
$"SELECT pr.*
|
||||||
FROM %s{revTable} pr
|
FROM %s{revTable} pr
|
||||||
INNER JOIN %s{entityTable} p ON p.data->>'Id' = pr.{entityTable}_id
|
INNER JOIN %s{entityTable} p ON p.data->>'Id' = pr.{entityTable}_id
|
||||||
WHERE p.{Document.Query.whereByWebLog}
|
WHERE p.{Query.whereByFields Any [ webLogField webLogId ]}
|
||||||
ORDER BY as_of DESC"
|
ORDER BY as_of DESC"
|
||||||
[ webLogParam webLogId ]
|
[ webLogParam webLogId ]
|
||||||
(fun rdr -> keyFunc (Map.getString $"{entityTable}_id" rdr), Map.toRevision rdr)
|
(fun rdr -> keyFunc (Map.getString $"{entityTable}_id" rdr), Map.toRevision rdr)
|
||||||
|
@ -68,7 +68,7 @@ type SQLitePageData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Count all pages shown in the page list for the given web log
|
/// Count all pages shown in the page list for the given web log
|
||||||
let countListed webLogId = backgroundTask {
|
let countListed webLogId = backgroundTask {
|
||||||
log.LogTrace "Page.countListed"
|
log.LogTrace "Page.countListed"
|
||||||
let! count = conn.countByFields Table.Page All [ webLogField webLogId; Field.EQ pgListName true ]
|
let! count = conn.countByFields Table.Page All [ webLogField webLogId; Field.Equal pgListName true ]
|
||||||
return int count
|
return int count
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,20 +107,20 @@ type SQLitePageData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find a page by its permalink for the given web log
|
/// Find a page by its permalink for the given web log
|
||||||
let findByPermalink (permalink: Permalink) webLogId =
|
let findByPermalink (permalink: Permalink) webLogId =
|
||||||
log.LogTrace "Page.findByPermalink"
|
log.LogTrace "Page.findByPermalink"
|
||||||
let fields = [ webLogField webLogId; Field.EQ linkName (string permalink) ]
|
let fields = [ webLogField webLogId; Field.Equal linkName (string permalink) ]
|
||||||
conn.customSingle
|
conn.customSingle
|
||||||
(Query.byFields (Query.find Table.Page) All fields) (addFieldParams fields []) pageWithoutLinks
|
(Query.byFields (Query.find Table.Page) All fields) (addFieldParams fields []) pageWithoutLinks
|
||||||
|
|
||||||
/// Find the current permalink within a set of potential prior permalinks for the given web log
|
/// Find the current permalink within a set of potential prior permalinks for the given web log
|
||||||
let findCurrentPermalink (permalinks: Permalink list) webLogId =
|
let findCurrentPermalink (permalinks: Permalink list) webLogId =
|
||||||
log.LogTrace "Page.findCurrentPermalink"
|
log.LogTrace "Page.findCurrentPermalink"
|
||||||
let linkSql, linkParams = inJsonArray Table.Page (nameof Page.Empty.PriorPermalinks) "link" permalinks
|
let fields =
|
||||||
conn.customSingle
|
[ webLogField webLogId
|
||||||
$"SELECT data->>'{linkName}' AS permalink
|
Field.InArray (nameof Page.Empty.PriorPermalinks) Table.Page (List.map (string >> box) permalinks) ]
|
||||||
FROM {Table.Page}
|
let query =
|
||||||
WHERE {Document.Query.whereByWebLog} AND {linkSql}"
|
(Query.statementWhere (Query.find Table.Page) (Query.whereByFields All fields))
|
||||||
(webLogParam webLogId :: linkParams)
|
.Replace("SELECT data", $"SELECT data->>'{linkName}' AS permalink")
|
||||||
Map.toPermalink
|
conn.customSingle query (addFieldParams fields []) Map.toPermalink
|
||||||
|
|
||||||
/// Get all complete pages for the given web log
|
/// Get all complete pages for the given web log
|
||||||
let findFullByWebLog webLogId = backgroundTask {
|
let findFullByWebLog webLogId = backgroundTask {
|
||||||
@ -133,7 +133,7 @@ type SQLitePageData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Get all listed pages for the given web log (without revisions or text)
|
/// Get all listed pages for the given web log (without revisions or text)
|
||||||
let findListed webLogId =
|
let findListed webLogId =
|
||||||
log.LogTrace "Page.findListed"
|
log.LogTrace "Page.findListed"
|
||||||
let fields = [ webLogField webLogId; Field.EQ pgListName true ]
|
let fields = [ webLogField webLogId; Field.Equal pgListName true ]
|
||||||
conn.customList
|
conn.customList
|
||||||
(sortedPages fields) (addFieldParams fields []) (fun rdr -> { fromData<Page> rdr with Text = "" })
|
(sortedPages fields) (addFieldParams fields []) (fun rdr -> { fromData<Page> rdr with Text = "" })
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The SELECT statement to retrieve posts with a web log ID parameter
|
/// The SELECT statement to retrieve posts with a web log ID parameter
|
||||||
let postByWebLog = Document.Query.selectByWebLog Table.Post
|
let postByWebLog =
|
||||||
|
Query.statementWhere
|
||||||
|
(Query.find Table.Post)
|
||||||
|
(Query.whereByFields Any [ { Field.Equal "WebLogId" "" with ParameterName = Some "@webLogId" } ])
|
||||||
|
|
||||||
/// Return a post with no revisions or prior permalinks
|
/// Return a post with no revisions or prior permalinks
|
||||||
let postWithoutLinks rdr =
|
let postWithoutLinks rdr =
|
||||||
@ -62,7 +65,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Count posts in a status for the given web log
|
/// Count posts in a status for the given web log
|
||||||
let countByStatus (status: PostStatus) webLogId = backgroundTask {
|
let countByStatus (status: PostStatus) webLogId = backgroundTask {
|
||||||
log.LogTrace "Post.countByStatus"
|
log.LogTrace "Post.countByStatus"
|
||||||
let! count = conn.countByFields Table.Post All [ webLogField webLogId; Field.EQ statName (string status) ]
|
let! count = conn.countByFields Table.Post All [ webLogField webLogId; Field.Equal statName (string status) ]
|
||||||
return int count
|
return int count
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +80,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find a post by its permalink for the given web log (excluding revisions)
|
/// Find a post by its permalink for the given web log (excluding revisions)
|
||||||
let findByPermalink (permalink: Permalink) webLogId =
|
let findByPermalink (permalink: Permalink) webLogId =
|
||||||
log.LogTrace "Post.findByPermalink"
|
log.LogTrace "Post.findByPermalink"
|
||||||
let fields = [ webLogField webLogId; Field.EQ linkName (string permalink) ]
|
let fields = [ webLogField webLogId; Field.Equal linkName (string permalink) ]
|
||||||
conn.customSingle
|
conn.customSingle
|
||||||
(Query.byFields (Query.find Table.Post) All fields) (addFieldParams fields []) postWithoutLinks
|
(Query.byFields (Query.find Table.Post) All fields) (addFieldParams fields []) postWithoutLinks
|
||||||
|
|
||||||
@ -111,13 +114,13 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find the current permalink from a list of potential prior permalinks for the given web log
|
/// Find the current permalink from a list of potential prior permalinks for the given web log
|
||||||
let findCurrentPermalink (permalinks: Permalink list) webLogId =
|
let findCurrentPermalink (permalinks: Permalink list) webLogId =
|
||||||
log.LogTrace "Post.findCurrentPermalink"
|
log.LogTrace "Post.findCurrentPermalink"
|
||||||
let linkSql, linkParams = inJsonArray Table.Post (nameof Post.Empty.PriorPermalinks) "link" permalinks
|
let fields =
|
||||||
conn.customSingle
|
[ webLogField webLogId
|
||||||
$"SELECT data->>'{linkName}' AS permalink
|
Field.InArray (nameof Post.Empty.PriorPermalinks) Table.Post (List.map (string >> box) permalinks) ]
|
||||||
FROM {Table.Post}
|
let query =
|
||||||
WHERE {Document.Query.whereByWebLog} AND {linkSql}"
|
(Query.statementWhere (Query.find Table.Post) (Query.whereByFields All fields))
|
||||||
(webLogParam webLogId :: linkParams)
|
.Replace("SELECT data", $"SELECT data->>'{linkName}' AS permalink")
|
||||||
Map.toPermalink
|
conn.customSingle query (addFieldParams fields []) Map.toPermalink
|
||||||
|
|
||||||
/// Get all complete posts for the given web log
|
/// Get all complete posts for the given web log
|
||||||
let findFullByWebLog webLogId = backgroundTask {
|
let findFullByWebLog webLogId = backgroundTask {
|
||||||
@ -130,12 +133,12 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Get a page of categorized posts for the given web log (excludes revisions)
|
/// Get a page of categorized posts for the given web log (excludes revisions)
|
||||||
let findPageOfCategorizedPosts webLogId (categoryIds: CategoryId list) pageNbr postsPerPage =
|
let findPageOfCategorizedPosts webLogId (categoryIds: CategoryId list) pageNbr postsPerPage =
|
||||||
log.LogTrace "Post.findPageOfCategorizedPosts"
|
log.LogTrace "Post.findPageOfCategorizedPosts"
|
||||||
let catSql, catParams = inJsonArray Table.Post (nameof Post.Empty.CategoryIds) "catId" categoryIds
|
let catIdField = Field.InArray (nameof Post.Empty.CategoryIds) Table.Post (List.map (string >> box) categoryIds)
|
||||||
conn.customList
|
conn.customList
|
||||||
$"""{publishedPostByWebLog} AND {catSql}
|
$"""{publishedPostByWebLog} AND {Query.whereByFields Any [ catIdField ]}
|
||||||
{Query.orderBy [ Field.Named $"{publishName} DESC" ] SQLite}
|
{Query.orderBy [ Field.Named $"{publishName} DESC" ] SQLite}
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
|
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
|
||||||
(webLogParam webLogId :: catParams)
|
(addFieldParams [ webLogField webLogId; catIdField ] [])
|
||||||
postWithoutLinks
|
postWithoutLinks
|
||||||
|
|
||||||
/// 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)
|
||||||
@ -162,12 +165,12 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Get a page of tagged posts for the given web log (excludes revisions)
|
/// Get a page of tagged posts for the given web log (excludes revisions)
|
||||||
let findPageOfTaggedPosts webLogId (tag : string) pageNbr postsPerPage =
|
let findPageOfTaggedPosts webLogId (tag : string) pageNbr postsPerPage =
|
||||||
log.LogTrace "Post.findPageOfTaggedPosts"
|
log.LogTrace "Post.findPageOfTaggedPosts"
|
||||||
let tagSql, tagParams = inJsonArray Table.Post (nameof Post.Empty.Tags) "tag" [ tag ]
|
let tagField = Field.InArray (nameof Post.Empty.Tags) Table.Post [ tag ]
|
||||||
conn.customList
|
conn.customList
|
||||||
$"""{publishedPostByWebLog} AND {tagSql}
|
$"""{publishedPostByWebLog} AND {Query.whereByFields Any [ tagField ]}
|
||||||
{Query.orderBy [ Field.Named $"{publishName} DESC" ] SQLite}
|
{Query.orderBy [ Field.Named $"{publishName} DESC" ] SQLite}
|
||||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
|
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"""
|
||||||
(webLogParam webLogId :: tagParams)
|
(addFieldParams [ webLogField webLogId; tagField ] [])
|
||||||
postWithoutLinks
|
postWithoutLinks
|
||||||
|
|
||||||
/// 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
|
||||||
@ -176,8 +179,8 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||||||
let adjacent op order =
|
let adjacent op order =
|
||||||
let fields = [
|
let fields = [
|
||||||
webLogField webLogId
|
webLogField webLogId
|
||||||
Field.EQ (nameof Post.Empty.Status) (string Published)
|
Field.Equal (nameof Post.Empty.Status) (string Published)
|
||||||
(if op = "<" then Field.LT else Field.GT) publishName (instantParam publishedOn)
|
(if op = "<" then Field.Less else Field.Greater) publishName (instantParam publishedOn)
|
||||||
]
|
]
|
||||||
conn.customSingle
|
conn.customSingle
|
||||||
(Query.byFields (Query.find Table.Post) All fields
|
(Query.byFields (Query.find Table.Post) All fields
|
||||||
|
@ -29,7 +29,7 @@ type SQLiteTagMapData(conn: SqliteConnection, log: ILogger) =
|
|||||||
let findByUrlValue (urlValue: string) webLogId =
|
let findByUrlValue (urlValue: string) webLogId =
|
||||||
log.LogTrace "TagMap.findByUrlValue"
|
log.LogTrace "TagMap.findByUrlValue"
|
||||||
conn.findFirstByFields<TagMap>
|
conn.findFirstByFields<TagMap>
|
||||||
Table.TagMap All [ webLogField webLogId; Field.EQ (nameof TagMap.Empty.UrlValue) urlValue ]
|
Table.TagMap All [ webLogField webLogId; Field.Equal (nameof TagMap.Empty.UrlValue) urlValue ]
|
||||||
|
|
||||||
/// Get all tag mappings for the given web log
|
/// Get all tag mappings for the given web log
|
||||||
let findByWebLog webLogId =
|
let findByWebLog webLogId =
|
||||||
@ -39,11 +39,8 @@ type SQLiteTagMapData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find any tag mappings in a list of tags for the given web log
|
/// Find any tag mappings in a list of tags for the given web log
|
||||||
let findMappingForTags (tags: string list) webLogId =
|
let findMappingForTags (tags: string list) webLogId =
|
||||||
log.LogTrace "TagMap.findMappingForTags"
|
log.LogTrace "TagMap.findMappingForTags"
|
||||||
let mapSql, mapParams = inClause $"AND data->>'{nameof TagMap.Empty.Tag}'" "tag" id tags
|
conn.findByFields<TagMap>
|
||||||
conn.customList
|
Table.TagMap All [ webLogField webLogId; Field.In (nameof TagMap.Empty.Tag) (List.map box tags) ]
|
||||||
$"{Document.Query.selectByWebLog Table.TagMap} {mapSql}"
|
|
||||||
(webLogParam webLogId :: mapParams)
|
|
||||||
fromData<TagMap>
|
|
||||||
|
|
||||||
/// Save a tag mapping
|
/// Save a tag mapping
|
||||||
let save (tagMap: TagMap) =
|
let save (tagMap: TagMap) =
|
||||||
|
@ -23,7 +23,8 @@ type SQLiteWebLogData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Delete a web log by its ID
|
/// Delete a web log by its ID
|
||||||
let delete webLogId =
|
let delete webLogId =
|
||||||
log.LogTrace "WebLog.delete"
|
log.LogTrace "WebLog.delete"
|
||||||
let webLogMatches = Query.whereByFields Any [ { Field.EQ "WebLogId" "" with ParameterName = Some "@webLogId" } ]
|
let webLogMatches =
|
||||||
|
Query.whereByFields Any [ { Field.Equal "WebLogId" "" with ParameterName = Some "@webLogId" } ]
|
||||||
let subQuery table = $"(SELECT data->>'Id' FROM {table} WHERE {webLogMatches})"
|
let subQuery table = $"(SELECT data->>'Id' FROM {table} WHERE {webLogMatches})"
|
||||||
Custom.nonQuery
|
Custom.nonQuery
|
||||||
$"""{Query.delete Table.PostComment} WHERE data ->> 'PostId' IN {subQuery Table.Post};
|
$"""{Query.delete Table.PostComment} WHERE data ->> 'PostId' IN {subQuery Table.Post};
|
||||||
@ -41,7 +42,7 @@ type SQLiteWebLogData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find a web log by its host (URL base)
|
/// Find a web log by its host (URL base)
|
||||||
let findByHost (url: string) =
|
let findByHost (url: string) =
|
||||||
log.LogTrace "WebLog.findByHost"
|
log.LogTrace "WebLog.findByHost"
|
||||||
conn.findFirstByFields<WebLog> Table.WebLog Any [ Field.EQ (nameof WebLog.Empty.UrlBase) url ]
|
conn.findFirstByFields<WebLog> Table.WebLog Any [ Field.Equal (nameof WebLog.Empty.UrlBase) url ]
|
||||||
|
|
||||||
/// Find a web log by its ID
|
/// Find a web log by its ID
|
||||||
let findById webLogId =
|
let findById webLogId =
|
||||||
|
@ -25,7 +25,7 @@ type SQLiteWebLogUserData(conn: SqliteConnection, log: ILogger) =
|
|||||||
log.LogTrace "WebLogUser.delete"
|
log.LogTrace "WebLogUser.delete"
|
||||||
match! findById userId webLogId with
|
match! findById userId webLogId with
|
||||||
| Some _ ->
|
| Some _ ->
|
||||||
let author = [ Field.EQ (nameof Page.Empty.AuthorId) (string userId) ]
|
let author = [ Field.Equal (nameof Page.Empty.AuthorId) (string userId) ]
|
||||||
let! pageCount = conn.countByFields Table.Page Any author
|
let! pageCount = conn.countByFields Table.Page Any author
|
||||||
let! postCount = conn.countByFields Table.Post Any author
|
let! postCount = conn.countByFields Table.Post Any author
|
||||||
if pageCount + postCount > 0 then
|
if pageCount + postCount > 0 then
|
||||||
@ -40,7 +40,7 @@ type SQLiteWebLogUserData(conn: SqliteConnection, log: ILogger) =
|
|||||||
let findByEmail (email: string) webLogId =
|
let findByEmail (email: string) webLogId =
|
||||||
log.LogTrace "WebLogUser.findByEmail"
|
log.LogTrace "WebLogUser.findByEmail"
|
||||||
conn.findFirstByFields
|
conn.findFirstByFields
|
||||||
Table.WebLogUser All [ webLogField webLogId; Field.EQ (nameof WebLogUser.Empty.Email) email ]
|
Table.WebLogUser All [ webLogField webLogId; Field.Equal (nameof WebLogUser.Empty.Email) email ]
|
||||||
|
|
||||||
/// Get all users for the given web log
|
/// Get all users for the given web log
|
||||||
let findByWebLog webLogId = backgroundTask {
|
let findByWebLog webLogId = backgroundTask {
|
||||||
@ -52,10 +52,11 @@ type SQLiteWebLogUserData(conn: SqliteConnection, log: ILogger) =
|
|||||||
/// Find the names of users by their IDs for the given web log
|
/// Find the names of users by their IDs for the given web log
|
||||||
let findNames webLogId (userIds: WebLogUserId list) =
|
let findNames webLogId (userIds: WebLogUserId list) =
|
||||||
log.LogTrace "WebLogUser.findNames"
|
log.LogTrace "WebLogUser.findNames"
|
||||||
let nameSql, nameParams = inClause $"AND data->>'{nameof WebLogUser.Empty.Id}'" "id" string userIds
|
let fields = [ webLogField webLogId; Field.In (nameof WebLogUser.Empty.Id) (List.map (string >> box) userIds) ]
|
||||||
|
let query = Query.statementWhere (Query.find Table.WebLogUser) (Query.whereByFields All fields)
|
||||||
conn.customList
|
conn.customList
|
||||||
$"{Document.Query.selectByWebLog Table.WebLogUser} {nameSql}"
|
query
|
||||||
(webLogParam webLogId :: nameParams)
|
(addFieldParams fields [])
|
||||||
(fun rdr ->
|
(fun rdr ->
|
||||||
let user = fromData<WebLogUser> rdr
|
let user = fromData<WebLogUser> rdr
|
||||||
{ Name = string user.Id; Value = user.DisplayName })
|
{ Name = string user.Id; Value = user.DisplayName })
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<PackageReference Include="Markdig" Version="0.37.0" />
|
<PackageReference Include="Markdig" Version="0.37.0" />
|
||||||
<PackageReference Include="Markdown.ColorCode" Version="2.2.2" />
|
<PackageReference Include="Markdown.ColorCode" Version="2.2.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NodaTime" Version="3.1.11" />
|
<PackageReference Include="NodaTime" Version="3.1.12" />
|
||||||
<PackageReference Update="FSharp.Core" Version="8.0.400" />
|
<PackageReference Update="FSharp.Core" Version="8.0.400" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user