Refine document queries
This commit is contained in:
parent
cc6f444b5f
commit
bb12d2525e
|
@ -200,11 +200,11 @@ type DistributedCache (connStr : string) =
|
|||
}
|
||||
|
||||
interface IDistributedCache with
|
||||
member this.Get key = get key CancellationToken.None |> sync
|
||||
member this.GetAsync (key, token) = get key token
|
||||
member this.Refresh key = refresh key CancellationToken.None |> sync
|
||||
member this.RefreshAsync (key, token) = refresh key token
|
||||
member this.Remove key = remove key CancellationToken.None |> sync
|
||||
member this.RemoveAsync (key, token) = remove key token
|
||||
member this.Set (key, value, options) = set key value options CancellationToken.None |> sync
|
||||
member this.SetAsync (key, value, options, token) = set key value options token
|
||||
member _.Get key = get key CancellationToken.None |> sync
|
||||
member _.GetAsync (key, token) = get key token
|
||||
member _.Refresh key = refresh key CancellationToken.None |> sync
|
||||
member _.RefreshAsync (key, token) = refresh key token
|
||||
member _.Remove key = remove key CancellationToken.None |> sync
|
||||
member _.RemoveAsync (key, token) = remove key token
|
||||
member _.Set (key, value, options) = set key value options CancellationToken.None |> sync
|
||||
member _.SetAsync (key, value, options, token) = set key value options token
|
||||
|
|
|
@ -9,18 +9,15 @@ open Npgsql.FSharp.Documents
|
|||
/// PostgreSQL myWebLog category data implementation
|
||||
type PostgresCategoryData (source : NpgsqlDataSource) =
|
||||
|
||||
/// Shorthand for turning a web log ID into a string
|
||||
let wls = WebLogId.toString
|
||||
|
||||
/// Count all categories for the given web log
|
||||
let countAll webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Query.countByContains Table.Category {| WebLogId = wls webLogId |}
|
||||
|> Query.countByContains Table.Category (webLogDoc webLogId)
|
||||
|
||||
/// Count all top-level categories for the given web log
|
||||
let countTopLevel webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Query.countByContains Table.Category {| WebLogId = wls webLogId; ParentId = None |}
|
||||
|> Query.countByContains Table.Category {| webLogDoc webLogId with ParentId = None |}
|
||||
|
||||
/// Retrieve all categories for the given web log in a DotLiquid-friendly format
|
||||
let findAllForView webLogId = backgroundTask {
|
||||
|
@ -30,7 +27,7 @@ type PostgresCategoryData (source : NpgsqlDataSource) =
|
|||
{Query.selectFromTable Table.Category}
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
ORDER BY LOWER(data->>'{nameof Category.empty.Name}')"""
|
||||
|> Sql.parameters [ "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync fromData<Category>
|
||||
let ordered = Utils.orderByHierarchy cats None None []
|
||||
let counts =
|
||||
|
@ -53,7 +50,7 @@ type PostgresCategoryData (source : NpgsqlDataSource) =
|
|||
AND ({catIdSql})"""
|
||||
|> Sql.parameters (
|
||||
("@criteria",
|
||||
Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString Published |})
|
||||
Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString Published |})
|
||||
:: catIdParams)
|
||||
|> Sql.executeRowAsync Map.toCount
|
||||
|> Async.AwaitTask
|
||||
|
|
|
@ -68,16 +68,17 @@ open Npgsql
|
|||
open Npgsql.FSharp
|
||||
open Npgsql.FSharp.Documents
|
||||
|
||||
/// Create a WHERE clause fragment for the web log ID
|
||||
let webLogWhere = "data ->> 'WebLogId' = @webLogId"
|
||||
|
||||
/// Create a SQL parameter for the web log ID
|
||||
let webLogIdParam webLogId =
|
||||
"@webLogId", Sql.string (WebLogId.toString webLogId)
|
||||
|
||||
/// Create an anonymous record with the given web log ID
|
||||
let webLogDoc webLogId =
|
||||
{| WebLogId = WebLogId.toString webLogId |}
|
||||
|
||||
/// Create a parameter for a web log document-contains query
|
||||
let webLogContains webLogId =
|
||||
Query.jsonbDocParam {| WebLogId = WebLogId.toString webLogId |}
|
||||
"@criteria", Query.jsonbDocParam (webLogDoc webLogId)
|
||||
|
||||
/// The name of the field to select to be able to use Map.toCount
|
||||
let countName = "the_count"
|
||||
|
@ -179,21 +180,21 @@ module Document =
|
|||
SELECT EXISTS (
|
||||
SELECT 1 FROM %s{table} WHERE id = @id AND {Query.whereDataContains "@criteria"}
|
||||
) AS {existsName}"""
|
||||
|> Sql.parameters [ "@id", Sql.string (keyFunc key); webLogIdParam webLogId ]
|
||||
|> Sql.parameters [ "@id", Sql.string (keyFunc key); webLogContains webLogId ]
|
||||
|> Sql.executeRowAsync Map.toExists
|
||||
|
||||
/// Find a document by its ID for the given web log
|
||||
let findByIdAndWebLog<'TKey, 'TDoc> source table (key : 'TKey) (keyFunc : 'TKey -> string) webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"""{Query.selectFromTable table} WHERE id = @id AND {Query.whereDataContains "@criteria"}"""
|
||||
|> Sql.parameters [ "@id", Sql.string (keyFunc key); "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ "@id", Sql.string (keyFunc key); webLogContains webLogId ]
|
||||
|> Sql.executeAsync fromData<'TDoc>
|
||||
|> tryHead
|
||||
|
||||
/// Find a document by its ID for the given web log
|
||||
let findByWebLog<'TDoc> source table webLogId : Task<'TDoc list> =
|
||||
Sql.fromDataSource source
|
||||
|> Query.findByContains table {| WebLogId = WebLogId.toString webLogId |}
|
||||
|> Query.findByContains table (webLogDoc webLogId)
|
||||
|
||||
|
||||
/// Functions to support revisions
|
||||
|
@ -209,13 +210,13 @@ module Revisions =
|
|||
/// Find all revisions for all posts for the given web log
|
||||
let findByWebLog<'TKey> source revTable entityTable (keyFunc : string -> 'TKey) webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"
|
||||
|> Sql.query $"""
|
||||
SELECT pr.*
|
||||
FROM %s{revTable} pr
|
||||
INNER JOIN %s{entityTable} p ON p.id = pr.{entityTable}_id
|
||||
WHERE p.{webLogWhere}
|
||||
ORDER BY as_of DESC"
|
||||
|> Sql.parameters [ webLogIdParam webLogId ]
|
||||
WHERE p.{Query.whereDataContains "@criteria"}
|
||||
ORDER BY as_of DESC"""
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync (fun row -> keyFunc (row.string $"{entityTable}_id"), Map.toRevision row)
|
||||
|
||||
/// Parameters for a revision INSERT statement
|
||||
|
|
|
@ -11,9 +11,6 @@ type PostgresPageData (source : NpgsqlDataSource) =
|
|||
|
||||
// SUPPORT FUNCTIONS
|
||||
|
||||
/// Shorthand for turning a web log ID into a string
|
||||
let wls = WebLogId.toString
|
||||
|
||||
/// Append revisions to a page
|
||||
let appendPageRevisions (page : Page) = backgroundTask {
|
||||
let! revisions = Revisions.findByEntityId source Table.PageRevision Table.Page page.Id PageId.toString
|
||||
|
@ -32,27 +29,28 @@ type PostgresPageData (source : NpgsqlDataSource) =
|
|||
let pageExists pageId webLogId =
|
||||
Document.existsByWebLog source Table.Page pageId PageId.toString webLogId
|
||||
|
||||
/// Select pages via a JSON document containment query
|
||||
let pageByCriteria =
|
||||
$"""{Query.selectFromTable Table.Page} WHERE {Query.whereDataContains "@criteria"}"""
|
||||
|
||||
// IMPLEMENTATION FUNCTIONS
|
||||
|
||||
/// Get all pages for a web log (without text or revisions)
|
||||
let all webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"""
|
||||
{Query.selectFromTable Table.Page}
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
ORDER BY LOWER(data->>'{nameof Page.empty.Title}')"""
|
||||
|> Sql.parameters [ "@criteria", webLogContains webLogId ]
|
||||
|> Sql.query $"{pageByCriteria} ORDER BY LOWER(data->>'{nameof Page.empty.Title}')"
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync fromData<Page>
|
||||
|
||||
/// Count all pages for the given web log
|
||||
let countAll webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Query.countByContains Table.Page {| WebLogId = wls webLogId |}
|
||||
|> Query.countByContains Table.Page (webLogDoc webLogId)
|
||||
|
||||
/// Count all pages shown in the page list for the given web log
|
||||
let countListed webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Query.countByContains Table.Page {| WebLogId = wls webLogId; IsInPageList = true |}
|
||||
|> Query.countByContains Table.Page {| webLogDoc webLogId with IsInPageList = true |}
|
||||
|
||||
/// Find a page by its ID (without revisions)
|
||||
let findById pageId webLogId =
|
||||
|
@ -79,7 +77,7 @@ type PostgresPageData (source : NpgsqlDataSource) =
|
|||
/// Find a page by its permalink for the given web log
|
||||
let findByPermalink permalink webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Query.findByContains<Page> Table.Page {| WebLogId = wls webLogId; Permalink = Permalink.toString permalink |}
|
||||
|> Query.findByContains<Page> Table.Page {| webLogDoc webLogId with Permalink = Permalink.toString permalink |}
|
||||
|> tryHead
|
||||
|
||||
/// Find the current permalink within a set of potential prior permalinks for the given web log
|
||||
|
@ -96,7 +94,7 @@ type PostgresPageData (source : NpgsqlDataSource) =
|
|||
FROM page
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
AND ({linkSql})"""
|
||||
|> Sql.parameters (("@criteria", webLogContains webLogId) :: linkParams)
|
||||
|> Sql.parameters (webLogContains webLogId :: linkParams)
|
||||
|> Sql.executeAsync Map.toPermalink
|
||||
|> tryHead
|
||||
}
|
||||
|
@ -114,26 +112,18 @@ type PostgresPageData (source : NpgsqlDataSource) =
|
|||
/// Get all listed pages for the given web log (without revisions or text)
|
||||
let findListed webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"""
|
||||
{Query.selectFromTable Table.Page}
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
ORDER BY LOWER(data->>'{nameof Page.empty.Title}')"""
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; IsInPageList = true |} ]
|
||||
|> Sql.query $"{pageByCriteria} ORDER BY LOWER(data->>'{nameof Page.empty.Title}')"
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with IsInPageList = true |} ]
|
||||
|> Sql.executeAsync pageWithoutText
|
||||
|
||||
/// Get a page of pages for the given web log (without revisions)
|
||||
let findPageOfPages webLogId pageNbr =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"""
|
||||
{Query.selectFromTable Table.Page}
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
|> Sql.query $"
|
||||
{pageByCriteria}
|
||||
ORDER BY LOWER(data->>'{nameof Page.empty.Title}')
|
||||
LIMIT @pageSize OFFSET @toSkip"""
|
||||
|> Sql.parameters
|
||||
[ "@criteria", webLogContains webLogId
|
||||
"@pageSize", Sql.int 26
|
||||
"@toSkip", Sql.int ((pageNbr - 1) * 25)
|
||||
]
|
||||
LIMIT @pageSize OFFSET @toSkip"
|
||||
|> Sql.parameters [ webLogContains webLogId; "@pageSize", Sql.int 26; "@toSkip", Sql.int ((pageNbr - 1) * 25) ]
|
||||
|> Sql.executeAsync fromData<Page>
|
||||
|
||||
/// The parameters for saving a page
|
||||
|
|
|
@ -12,9 +12,6 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
|
||||
// SUPPORT FUNCTIONS
|
||||
|
||||
/// Shorthand for turning a web log ID into a string
|
||||
let wls = WebLogId.toString
|
||||
|
||||
/// Append revisions to a post
|
||||
let appendPostRevisions (post : Post) = backgroundTask {
|
||||
let! revisions = Revisions.findByEntityId source Table.PostRevision Table.Post post.Id PostId.toString
|
||||
|
@ -45,7 +42,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
|> Sql.query
|
||||
$"""SELECT COUNT(id) AS {countName} FROM {Table.Post} WHERE {Query.whereDataContains "@criteria"}"""
|
||||
|> Sql.parameters
|
||||
[ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString status |} ]
|
||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString status |} ]
|
||||
|> Sql.executeRowAsync Map.toCount
|
||||
|
||||
/// Find a post by its ID for the given web log (excluding revisions)
|
||||
|
@ -57,7 +54,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
Sql.fromDataSource source
|
||||
|> Sql.query postsByCriteria
|
||||
|> Sql.parameters
|
||||
[ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Permalink = Permalink.toString permalink |} ]
|
||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Permalink = Permalink.toString permalink |} ]
|
||||
|> Sql.executeAsync fromData<Post>
|
||||
|> tryHead
|
||||
|
||||
|
@ -99,7 +96,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
FROM {Table.Post}
|
||||
WHERE {Query.whereDataContains "@criteria"}
|
||||
AND ({linkSql})"""
|
||||
|> Sql.parameters (("@criteria", webLogContains webLogId) :: linkParams)
|
||||
|> Sql.parameters (webLogContains webLogId :: linkParams)
|
||||
|> Sql.executeAsync Map.toPermalink
|
||||
|> tryHead
|
||||
}
|
||||
|
@ -124,7 +121,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
ORDER BY published_on DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
|> Sql.parameters (
|
||||
("@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString Published |})
|
||||
("@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString Published |})
|
||||
:: catParams)
|
||||
|> Sql.executeAsync fromData<Post>
|
||||
|
||||
|
@ -136,7 +133,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
ORDER BY data->>'{nameof Post.empty.PublishedOn}' DESC NULLS FIRST,
|
||||
data->>'{nameof Post.empty.UpdatedOn}'
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
|> Sql.parameters [ "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync postWithoutText
|
||||
|
||||
/// Get a page of published posts for the given web log (excludes revisions)
|
||||
|
@ -147,7 +144,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
ORDER BY data->>'{nameof Post.empty.PublishedOn}' DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
|> Sql.parameters
|
||||
[ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString Published |} ]
|
||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString Published |} ]
|
||||
|> Sql.executeAsync fromData<Post>
|
||||
|
||||
/// Get a page of tagged posts for the given web log (excludes revisions and prior permalinks)
|
||||
|
@ -159,7 +156,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
ORDER BY data->>'{nameof Post.empty.PublishedOn}' DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
|> Sql.parameters
|
||||
[ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString Published |}
|
||||
[ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString Published |}
|
||||
"@tag", Sql.jsonb tag
|
||||
]
|
||||
|> Sql.executeAsync fromData<Post>
|
||||
|
@ -167,7 +164,7 @@ type PostgresPostData (source : NpgsqlDataSource) =
|
|||
/// Find the next newest and oldest post from a publish date for the given web log
|
||||
let findSurroundingPosts webLogId (publishedOn : Instant) = backgroundTask {
|
||||
let queryParams () = Sql.parameters [
|
||||
"@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Status = PostStatus.toString Published |}
|
||||
"@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Status = PostStatus.toString Published |}
|
||||
typedParam "publishedOn" publishedOn
|
||||
]
|
||||
let! older =
|
||||
|
|
|
@ -9,9 +9,6 @@ open Npgsql.FSharp.Documents
|
|||
/// PostgreSQL myWebLog tag mapping data implementation
|
||||
type PostgresTagMapData (source : NpgsqlDataSource) =
|
||||
|
||||
/// Shorthand for turning a web log ID into a string
|
||||
let wls = WebLogId.toString
|
||||
|
||||
/// A query to select tag map(s) by JSON document containment criteria
|
||||
let tagMapByCriteria =
|
||||
$"""{Query.selectFromTable Table.TagMap} WHERE {Query.whereDataContains "@criteria"}"""
|
||||
|
@ -33,7 +30,7 @@ type PostgresTagMapData (source : NpgsqlDataSource) =
|
|||
let findByUrlValue (urlValue : string) webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query tagMapByCriteria
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; UrlValue = urlValue |} ]
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with UrlValue = urlValue |} ]
|
||||
|> Sql.executeAsync fromData<TagMap>
|
||||
|> tryHead
|
||||
|
||||
|
@ -41,7 +38,7 @@ type PostgresTagMapData (source : NpgsqlDataSource) =
|
|||
let findByWebLog webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"{tagMapByCriteria} ORDER BY data->>'tag'"
|
||||
|> Sql.parameters [ "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync fromData<TagMap>
|
||||
|
||||
/// Find any tag mappings in a list of tags for the given web log
|
||||
|
@ -49,7 +46,7 @@ type PostgresTagMapData (source : NpgsqlDataSource) =
|
|||
let tagSql, tagParams = jsonArrayInClause (nameof TagMap.empty.Tag) id tags
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"{tagMapByCriteria} AND ({tagSql})"
|
||||
|> Sql.parameters (("@criteria", webLogContains webLogId) :: tagParams)
|
||||
|> Sql.parameters (webLogContains webLogId :: tagParams)
|
||||
|> Sql.executeAsync fromData<TagMap>
|
||||
|
||||
/// The parameters for saving a tag mapping
|
||||
|
|
|
@ -33,7 +33,7 @@ type PostgresWebLogData (source : NpgsqlDataSource) =
|
|||
DELETE FROM {Table.Upload} WHERE web_log_id = @webLogId;
|
||||
DELETE FROM {Table.WebLogUser} WHERE {criteria};
|
||||
DELETE FROM {Table.WebLog} WHERE id = @webLogId"
|
||||
|> Sql.parameters [ webLogIdParam webLogId; "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ webLogIdParam webLogId; webLogContains webLogId ]
|
||||
|> Sql.executeNonQueryAsync
|
||||
()
|
||||
}
|
||||
|
|
|
@ -9,9 +9,6 @@ open Npgsql.FSharp.Documents
|
|||
/// PostgreSQL myWebLog user data implementation
|
||||
type PostgresWebLogUserData (source : NpgsqlDataSource) =
|
||||
|
||||
/// Shorthand for making a web log ID into a string
|
||||
let wls = WebLogId.toString
|
||||
|
||||
/// Query to get users by JSON document containment criteria
|
||||
let userByCriteria =
|
||||
$"""{Query.selectFromTable Table.WebLogUser} WHERE {Query.whereDataContains "@criteria"}"""
|
||||
|
@ -51,7 +48,7 @@ type PostgresWebLogUserData (source : NpgsqlDataSource) =
|
|||
let findByEmail (email : string) webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query userByCriteria
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| WebLogId = wls webLogId; Email = email |} ]
|
||||
|> Sql.parameters [ "@criteria", Query.jsonbDocParam {| webLogDoc webLogId with Email = email |} ]
|
||||
|> Sql.executeAsync fromData<WebLogUser>
|
||||
|> tryHead
|
||||
|
||||
|
@ -59,7 +56,7 @@ type PostgresWebLogUserData (source : NpgsqlDataSource) =
|
|||
let findByWebLog webLogId =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"{userByCriteria} ORDER BY LOWER(data->>'{nameof WebLogUser.empty.PreferredName}')"
|
||||
|> Sql.parameters [ "@criteria", webLogContains webLogId ]
|
||||
|> Sql.parameters [ webLogContains webLogId ]
|
||||
|> Sql.executeAsync fromData<WebLogUser>
|
||||
|
||||
/// Find the names of users by their IDs for the given web log
|
||||
|
@ -68,7 +65,7 @@ type PostgresWebLogUserData (source : NpgsqlDataSource) =
|
|||
let! users =
|
||||
Sql.fromDataSource source
|
||||
|> Sql.query $"{userByCriteria} {idSql}"
|
||||
|> Sql.parameters (("@criteria", webLogContains webLogId) :: idParams)
|
||||
|> Sql.parameters (webLogContains webLogId :: idParams)
|
||||
|> Sql.executeAsync fromData<WebLogUser>
|
||||
return
|
||||
users
|
||||
|
|
Loading…
Reference in New Issue
Block a user