Version 2.1 #41
|
@ -128,7 +128,7 @@ type IPostData =
|
|||
abstract member FindPageOfCategorizedPosts :
|
||||
WebLogId -> CategoryId list -> pageNbr: int -> postsPerPage: int -> Task<Post list>
|
||||
|
||||
/// Find posts to be displayed on an admin page (excluding revisions and prior permalinks)
|
||||
/// Find posts to be displayed on an admin page (excluding text, revisions, and prior permalinks)
|
||||
abstract member FindPageOfPosts : WebLogId -> pageNbr: int -> postsPerPage: int -> Task<Post list>
|
||||
|
||||
/// Find posts to be displayed on a page (excluding revisions and prior permalinks)
|
||||
|
|
|
@ -5,7 +5,7 @@ open BitBadger.Documents.Postgres
|
|||
open Microsoft.Extensions.Logging
|
||||
open MyWebLog
|
||||
open MyWebLog.Data
|
||||
open NodaTime.Text
|
||||
open NodaTime
|
||||
open Npgsql.FSharp
|
||||
|
||||
/// PostgreSQL myWebLog post data implementation
|
||||
|
@ -20,9 +20,13 @@ type PostgresPostData(log: ILogger) =
|
|||
return { post with Revisions = revisions }
|
||||
}
|
||||
|
||||
/// Return a post with no revisions or text
|
||||
/// Return a post with no revisions or prior permalinks
|
||||
let postWithoutLinks row =
|
||||
{ fromData<Post> row with PriorPermalinks = [] }
|
||||
|
||||
/// Return a post with no revisions, prior permalinks, or text
|
||||
let postWithoutText row =
|
||||
{ fromData<Post> row with Text = "" }
|
||||
{ postWithoutLinks row with Text = "" }
|
||||
|
||||
/// Update a post's revisions
|
||||
let updatePostRevisions (postId: PostId) oldRevs newRevs =
|
||||
|
@ -36,6 +40,13 @@ type PostgresPostData(log: ILogger) =
|
|||
|
||||
// IMPLEMENTATION FUNCTIONS
|
||||
|
||||
/// Add a post
|
||||
let add (post : Post) = backgroundTask {
|
||||
log.LogTrace "Post.add"
|
||||
do! insert Table.Post { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id [] post.Revisions
|
||||
}
|
||||
|
||||
/// Count posts in a status for the given web log
|
||||
let countByStatus (status: PostStatus) webLogId =
|
||||
log.LogTrace "Post.countByStatus"
|
||||
|
@ -55,7 +66,7 @@ type PostgresPostData(log: ILogger) =
|
|||
Custom.single
|
||||
(selectWithCriteria Table.Post)
|
||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Permalink = permalink |} ]
|
||||
(fun row -> { fromData<Post> row with PriorPermalinks = [] })
|
||||
postWithoutLinks
|
||||
|
||||
/// Find a complete post by its ID for the given web log
|
||||
let findFullById postId webLogId = backgroundTask {
|
||||
|
@ -118,7 +129,7 @@ type PostgresPostData(log: ILogger) =
|
|||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; catParam ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// Get a page of posts for the given web log (excludes text and revisions)
|
||||
let findPageOfPosts webLogId pageNbr postsPerPage =
|
||||
|
@ -139,7 +150,7 @@ type PostgresPostData(log: ILogger) =
|
|||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |} ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// Get a page of tagged posts for the given web log (excludes revisions and prior permalinks)
|
||||
let findPageOfTaggedPosts webLogId (tag: string) pageNbr postsPerPage =
|
||||
|
@ -150,40 +161,32 @@ type PostgresPostData(log: ILogger) =
|
|||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}; jsonParam "@tag" [| tag |] ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// 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: Instant) = backgroundTask {
|
||||
log.LogTrace "Post.findSurroundingPosts"
|
||||
let queryParams () =
|
||||
[ jsonParam "@criteria" {| webLogDoc webLogId with Status = Published |}
|
||||
"@publishedOn", Sql.string ((InstantPattern.General.Format publishedOn)[..19]) ]
|
||||
let pubField = nameof Post.Empty.PublishedOn
|
||||
let! older =
|
||||
Custom.list
|
||||
$"{selectWithCriteria Table.Post}
|
||||
AND SUBSTR(data ->> '{pubField}', 1, 19) < @publishedOn
|
||||
ORDER BY data ->> '{pubField}' DESC
|
||||
LIMIT 1"
|
||||
(queryParams ())
|
||||
fromData<Post>
|
||||
let! newer =
|
||||
Custom.list
|
||||
$"{selectWithCriteria Table.Post}
|
||||
AND SUBSTR(data ->> '{pubField}', 1, 19) > @publishedOn
|
||||
ORDER BY data ->> '{pubField}'
|
||||
LIMIT 1"
|
||||
(queryParams ())
|
||||
fromData<Post>
|
||||
"@publishedOn", Sql.timestamptz (publishedOn.ToDateTimeOffset()) ]
|
||||
let query op direction =
|
||||
$"{selectWithCriteria Table.Post}
|
||||
AND (data ->> '{nameof Post.Empty.PublishedOn}')::timestamp with time zone %s{op} @publishedOn
|
||||
ORDER BY data ->> '{nameof Post.Empty.PublishedOn}' %s{direction}
|
||||
LIMIT 1"
|
||||
let! older = Custom.list (query "<" "DESC") (queryParams ()) postWithoutLinks
|
||||
let! newer = Custom.list (query ">" "") (queryParams ()) postWithoutLinks
|
||||
return List.tryHead older, List.tryHead newer
|
||||
}
|
||||
|
||||
/// Save a post
|
||||
let save (post : Post) = backgroundTask {
|
||||
/// Update a post
|
||||
let update (post : Post) = backgroundTask {
|
||||
log.LogTrace "Post.save"
|
||||
let! oldPost = findFullById post.Id post.WebLogId
|
||||
do! save Table.Post { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id (match oldPost with Some p -> p.Revisions | None -> []) post.Revisions
|
||||
match! findFullById post.Id post.WebLogId with
|
||||
| Some oldPost ->
|
||||
do! Update.byId Table.Post post.Id { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id oldPost.Revisions post.Revisions
|
||||
| None -> ()
|
||||
}
|
||||
|
||||
/// Restore posts from a backup
|
||||
|
@ -212,7 +215,7 @@ type PostgresPostData(log: ILogger) =
|
|||
}
|
||||
|
||||
interface IPostData with
|
||||
member _.Add post = save post
|
||||
member _.Add post = add post
|
||||
member _.CountByStatus status webLogId = countByStatus status webLogId
|
||||
member _.Delete postId webLogId = delete postId webLogId
|
||||
member _.FindById postId webLogId = findById postId webLogId
|
||||
|
@ -229,5 +232,5 @@ type PostgresPostData(log: ILogger) =
|
|||
findPageOfTaggedPosts webLogId tag pageNbr postsPerPage
|
||||
member _.FindSurroundingPosts webLogId publishedOn = findSurroundingPosts webLogId publishedOn
|
||||
member _.Restore posts = restore posts
|
||||
member _.Update post = save post
|
||||
member _.Update post = update post
|
||||
member _.UpdatePriorPermalinks postId webLogId permalinks = updatePriorPermalinks postId webLogId permalinks
|
||||
|
|
|
@ -649,7 +649,8 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
getAll (objList categoryIds) (nameof Post.Empty.CategoryIds)
|
||||
filter [ nameof Post.Empty.WebLogId, webLogId :> obj
|
||||
nameof Post.Empty.Status, Published ]
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
distinct
|
||||
orderByDescending (nameof Post.Empty.PublishedOn)
|
||||
skip ((pageNbr - 1) * postsPerPage)
|
||||
|
@ -660,7 +661,9 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
member _.FindPageOfPosts webLogId pageNbr postsPerPage = rethink<Post list> {
|
||||
withTable Table.Post
|
||||
getAll [ webLogId ] (nameof Post.Empty.WebLogId)
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.Text, "")
|
||||
.With(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
orderByFuncDescending (fun row ->
|
||||
row[nameof Post.Empty.PublishedOn].Default_(nameof Post.Empty.UpdatedOn) :> obj)
|
||||
skip ((pageNbr - 1) * postsPerPage)
|
||||
|
@ -672,7 +675,8 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
withTable Table.Post
|
||||
getAll [ webLogId ] (nameof Post.Empty.WebLogId)
|
||||
filter (nameof Post.Empty.Status) Published
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
orderByDescending (nameof Post.Empty.PublishedOn)
|
||||
skip ((pageNbr - 1) * postsPerPage)
|
||||
limit (postsPerPage + 1)
|
||||
|
@ -684,7 +688,8 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
getAll [ tag ] (nameof Post.Empty.Tags)
|
||||
filter [ nameof Post.Empty.WebLogId, webLogId :> obj
|
||||
nameof Post.Empty.Status, Published ]
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
orderByDescending (nameof Post.Empty.PublishedOn)
|
||||
skip ((pageNbr - 1) * postsPerPage)
|
||||
limit (postsPerPage + 1)
|
||||
|
@ -697,7 +702,8 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
withTable Table.Post
|
||||
getAll [ webLogId ] (nameof Post.Empty.WebLogId)
|
||||
filter (fun row -> row[nameof Post.Empty.PublishedOn].Lt publishedOn :> obj)
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
orderByDescending (nameof Post.Empty.PublishedOn)
|
||||
limit 1
|
||||
result; withRetryDefault
|
||||
|
@ -708,7 +714,8 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
withTable Table.Post
|
||||
getAll [ webLogId ] (nameof Post.Empty.WebLogId)
|
||||
filter (fun row -> row[nameof Post.Empty.PublishedOn].Gt publishedOn :> obj)
|
||||
without [ nameof Post.Empty.PriorPermalinks; nameof Post.Empty.Revisions ]
|
||||
merge (r.HashMap(nameof Post.Empty.PriorPermalinks, [||])
|
||||
.With(nameof Post.Empty.Revisions, [||]))
|
||||
orderBy (nameof Post.Empty.PublishedOn)
|
||||
limit 1
|
||||
result; withRetryDefault
|
||||
|
@ -726,22 +733,20 @@ type RethinkDbData(conn: Net.IConnection, config: DataConfig, log: ILogger<Rethi
|
|||
}
|
||||
}
|
||||
|
||||
member _.Update post = rethink {
|
||||
withTable Table.Post
|
||||
get post.Id
|
||||
replace post
|
||||
write; withRetryDefault; ignoreResult conn
|
||||
member this.Update post = backgroundTask {
|
||||
match! this.FindById post.Id post.WebLogId with
|
||||
| Some _ ->
|
||||
do! rethink {
|
||||
withTable Table.Post
|
||||
get post.Id
|
||||
replace post
|
||||
write; withRetryDefault; ignoreResult conn
|
||||
}
|
||||
| None -> ()
|
||||
}
|
||||
|
||||
member _.UpdatePriorPermalinks postId webLogId permalinks = backgroundTask {
|
||||
match! (
|
||||
rethink<Post> {
|
||||
withTable Table.Post
|
||||
get postId
|
||||
without [ nameof Post.Empty.Revisions; nameof Post.Empty.PriorPermalinks ]
|
||||
resultOption; withRetryOptionDefault
|
||||
}
|
||||
|> verifyWebLog webLogId (_.WebLogId)) conn with
|
||||
member this.UpdatePriorPermalinks postId webLogId permalinks = backgroundTask {
|
||||
match! this.FindById postId webLogId with
|
||||
| Some _ ->
|
||||
do! rethink {
|
||||
withTable Table.Post
|
||||
|
|
|
@ -33,6 +33,14 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
/// The SELECT statement to retrieve posts with a web log ID parameter
|
||||
let postByWebLog = Document.Query.selectByWebLog Table.Post
|
||||
|
||||
/// Return a post with no revisions or prior permalinks
|
||||
let postWithoutLinks rdr =
|
||||
{ fromData<Post> rdr with PriorPermalinks = [] }
|
||||
|
||||
/// Return a post with no revisions, prior permalinks, or text
|
||||
let postWithoutText rdr =
|
||||
{ postWithoutLinks rdr with Text = "" }
|
||||
|
||||
/// The SELECT statement to retrieve published posts with a web log ID parameter
|
||||
let publishedPostByWebLog =
|
||||
$"""{postByWebLog} AND {Query.whereByField (Field.EQ statName "") $"'{string Published}'"}"""
|
||||
|
@ -44,6 +52,13 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
|
||||
// IMPLEMENTATION FUNCTIONS
|
||||
|
||||
/// Add a post
|
||||
let add (post: Post) = backgroundTask {
|
||||
log.LogTrace "Post.add"
|
||||
do! conn.insert Table.Post { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id [] post.Revisions
|
||||
}
|
||||
|
||||
/// Count posts in a status for the given web log
|
||||
let countByStatus (status: PostStatus) webLogId =
|
||||
log.LogTrace "Post.countByStatus"
|
||||
|
@ -68,7 +83,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
conn.customSingle
|
||||
$"""{Document.Query.selectByWebLog Table.Post} AND {Query.whereByField linkParam "@link"}"""
|
||||
(addFieldParam "@link" linkParam [ webLogParam webLogId ])
|
||||
(fun rdr -> { fromData<Post> rdr with PriorPermalinks = [] })
|
||||
postWithoutLinks
|
||||
|
||||
/// Find a complete post by its ID for the given web log
|
||||
let findFullById postId webLogId = backgroundTask {
|
||||
|
@ -123,7 +138,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
ORDER BY {publishField} DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
(webLogParam webLogId :: catParams)
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// Get a page of posts for the given web log (excludes text and revisions)
|
||||
let findPageOfPosts webLogId pageNbr postsPerPage =
|
||||
|
@ -133,7 +148,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
ORDER BY {publishField} DESC NULLS FIRST, data ->> '{nameof Post.Empty.UpdatedOn}'
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
[ webLogParam webLogId ]
|
||||
(fun rdr -> { fromData<Post> rdr with Text = "" })
|
||||
postWithoutText
|
||||
|
||||
/// Get a page of published posts for the given web log (excludes revisions)
|
||||
let findPageOfPublishedPosts webLogId pageNbr postsPerPage =
|
||||
|
@ -143,7 +158,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
ORDER BY {publishField} DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
[ webLogParam webLogId ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// Get a page of tagged posts for the given web log (excludes revisions)
|
||||
let findPageOfTaggedPosts webLogId (tag : string) pageNbr postsPerPage =
|
||||
|
@ -154,7 +169,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
ORDER BY {publishField} DESC
|
||||
LIMIT {postsPerPage + 1} OFFSET {(pageNbr - 1) * postsPerPage}"
|
||||
(webLogParam webLogId :: tagParams)
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
|
||||
/// Find the next newest and oldest post from a publish date for the given web log
|
||||
let findSurroundingPosts webLogId (publishedOn : Instant) = backgroundTask {
|
||||
|
@ -163,27 +178,29 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
conn.customSingle
|
||||
$"{publishedPostByWebLog} AND {publishField} < @publishedOn ORDER BY {publishField} DESC LIMIT 1"
|
||||
[ webLogParam webLogId; SqliteParameter("@publishedOn", instantParam publishedOn) ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
let! newer =
|
||||
conn.customSingle
|
||||
$"{publishedPostByWebLog} AND {publishField} > @publishedOn ORDER BY {publishField} LIMIT 1"
|
||||
[ webLogParam webLogId; SqliteParameter("@publishedOn", instantParam publishedOn) ]
|
||||
fromData<Post>
|
||||
postWithoutLinks
|
||||
return older, newer
|
||||
}
|
||||
|
||||
/// Save a post
|
||||
let save (post: Post) = backgroundTask {
|
||||
log.LogTrace "Post.save"
|
||||
let! oldPost = findFullById post.Id post.WebLogId
|
||||
do! conn.save Table.Post { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id (match oldPost with Some p -> p.Revisions | None -> []) post.Revisions
|
||||
/// Update a post
|
||||
let update (post: Post) = backgroundTask {
|
||||
log.LogTrace "Post.update"
|
||||
match! findFullById post.Id post.WebLogId with
|
||||
| Some oldPost ->
|
||||
do! conn.updateById Table.Post post.Id { post with Revisions = [] }
|
||||
do! updatePostRevisions post.Id oldPost.Revisions post.Revisions
|
||||
| None -> ()
|
||||
}
|
||||
|
||||
/// Restore posts from a backup
|
||||
let restore posts = backgroundTask {
|
||||
log.LogTrace "Post.restore"
|
||||
for post in posts do do! save post
|
||||
for post in posts do do! add post
|
||||
}
|
||||
|
||||
/// Update prior permalinks for a post
|
||||
|
@ -196,7 +213,7 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
}
|
||||
|
||||
interface IPostData with
|
||||
member _.Add post = save post
|
||||
member _.Add post = add post
|
||||
member _.CountByStatus status webLogId = countByStatus status webLogId
|
||||
member _.Delete postId webLogId = delete postId webLogId
|
||||
member _.FindById postId webLogId = findById postId webLogId
|
||||
|
@ -213,5 +230,5 @@ type SQLitePostData(conn: SqliteConnection, log: ILogger) =
|
|||
findPageOfTaggedPosts webLogId tag pageNbr postsPerPage
|
||||
member _.FindSurroundingPosts webLogId publishedOn = findSurroundingPosts webLogId publishedOn
|
||||
member _.Restore posts = restore posts
|
||||
member _.Update post = save post
|
||||
member _.Update post = update post
|
||||
member _.UpdatePriorPermalinks postId webLogId permalinks = updatePriorPermalinks postId webLogId permalinks
|
||||
|
|
|
@ -24,9 +24,31 @@ let episode2 = PostId "l4_Eh4aFO06SqqJjOymNzA"
|
|||
/// The ID of "Something May Happen" post
|
||||
let something = PostId "QweKbWQiOkqqrjEdgP9wwg"
|
||||
|
||||
/// The published instant for "Something May Happen" post
|
||||
let somethingPublished = Instant.FromDateTimeOffset(DateTimeOffset.Parse "2024-01-20T22:32:59Z")
|
||||
|
||||
/// The ID of "An Incomplete Thought" post
|
||||
let incomplete = PostId "VweKbWQiOkqqrjEdgP9wwg"
|
||||
|
||||
/// The ID of "Test Post 1" post
|
||||
let testPost1 = PostId "RCsCU2puYEmkpzotoi8p4g"
|
||||
|
||||
/// The published instant for "Test Post 1" post
|
||||
let testPost1Published = Instant.FromDateTimeOffset(DateTimeOffset.Parse "2024-01-20T22:17:29Z")
|
||||
|
||||
/// The category IDs for "Spitball" (parent) and "Moonshot"
|
||||
let testCatIds = [ CategoryId "jw6N69YtTEWVHAO33jHU-w"; CategoryId "ScVpyu1e7UiP7bDdge3ZEw" ]
|
||||
|
||||
/// Ensure that a list of posts has text for each post
|
||||
let ensureHasText (posts: Post list) =
|
||||
for post in posts do Expect.isNotEmpty post.Text $"Text should not be blank (post ID {post.Id})"
|
||||
|
||||
/// Ensure that a list of posts has no revisions or prior permalinks
|
||||
let ensureEmpty posts =
|
||||
for post in posts do
|
||||
Expect.isEmpty post.Revisions $"There should have been no revisions (post ID {post.Id})"
|
||||
Expect.isEmpty post.PriorPermalinks $"There should have been no prior permalinks (post ID {post.Id})"
|
||||
|
||||
let ``Add succeeds`` (data: IData) = task {
|
||||
let post =
|
||||
{ Id = PostId "a-new-post"
|
||||
|
@ -109,8 +131,7 @@ let ``FindById succeeds when a post is found`` (data: IData) = task {
|
|||
it.Metadata
|
||||
[ { Name = "Density"; Value = "Non-existent" }; { Name = "Intensity"; Value = "Low" } ]
|
||||
"Metadata is incorrect"
|
||||
Expect.isEmpty it.PriorPermalinks "Prior permalinks should have been empty"
|
||||
Expect.isEmpty it.Revisions "Revisions should have been empty"
|
||||
ensureEmpty [ it ]
|
||||
}
|
||||
|
||||
let ``FindById succeeds when a post is not found (incorrect weblog)`` (data: IData) = task {
|
||||
|
@ -128,8 +149,7 @@ let ``FindByPermalink succeeds when a post is found`` (data: IData) = task {
|
|||
Expect.isSome post "A post should have been returned"
|
||||
let it = post.Value
|
||||
Expect.equal it.Id episode1 "The wrong post was retrieved"
|
||||
Expect.isEmpty it.PriorPermalinks "Prior permalinks should have been empty"
|
||||
Expect.isEmpty it.Revisions "Revisions should have been empty"
|
||||
ensureEmpty [ it ]
|
||||
}
|
||||
|
||||
let ``FindByPermalink succeeds when a post is not found (incorrect weblog)`` (data: IData) = task {
|
||||
|
@ -173,8 +193,8 @@ let ``FindFullById succeeds when a post is not found`` (data: IData) = task {
|
|||
|
||||
let ``FindFullByWebLog succeeds when posts are found`` (data: IData) = task {
|
||||
let! posts = data.Post.FindFullByWebLog rootId
|
||||
Expect.hasLength posts 4 "There should have been 4 posts returned"
|
||||
let allPosts = [ testPost1; episode1; episode2; something ]
|
||||
Expect.hasLength posts 5 "There should have been 5 posts returned"
|
||||
let allPosts = [ testPost1; episode1; episode2; something; incomplete ]
|
||||
posts |> List.iter (fun it ->
|
||||
Expect.contains allPosts it.Id $"Post ID {it.Id} unexpected"
|
||||
if it.Id = episode1 then
|
||||
|
@ -187,3 +207,225 @@ let ``FindFullByWebLog succeeds when posts are not found`` (data: IData) = task
|
|||
let! posts = data.Post.FindFullByWebLog (WebLogId "nonexistent")
|
||||
Expect.isEmpty posts "No posts should have been retrieved"
|
||||
}
|
||||
|
||||
let ``FindPageOfCategorizedPosts succeeds when posts are found`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfCategorizedPosts rootId testCatIds 1 1
|
||||
Expect.hasLength posts 2 "There should be 2 posts returned"
|
||||
Expect.equal posts[0].Id something "The wrong post was returned for page 1"
|
||||
ensureEmpty posts
|
||||
let! posts = data.Post.FindPageOfCategorizedPosts rootId testCatIds 2 1
|
||||
Expect.hasLength posts 1 "There should be 1 post returned"
|
||||
Expect.equal posts[0].Id testPost1 "The wrong post was returned for page 2"
|
||||
ensureEmpty posts
|
||||
}
|
||||
|
||||
let ``FindPageOfCategorizedPosts succeeds when finding a too-high page number`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfCategorizedPosts rootId testCatIds 17 2
|
||||
Expect.hasLength posts 0 "There should have been no posts returned (not enough posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfCategorizedPosts succeeds when a category has no posts`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfCategorizedPosts rootId [ CategoryId "nope" ] 1 1
|
||||
Expect.hasLength posts 0 "There should have been no posts returned (none match)"
|
||||
}
|
||||
|
||||
let ``FindPageOfPosts succeeds when posts are found`` (data: IData) = task {
|
||||
let ensureNoText (posts: Post list) =
|
||||
for post in posts do Expect.equal post.Text "" $"There should be no text (post ID {post.Id})"
|
||||
let! posts = data.Post.FindPageOfPosts rootId 1 2
|
||||
Expect.hasLength posts 3 "There should have been 3 posts returned for page 1"
|
||||
Expect.equal posts[0].Id incomplete "Page 1, post 1 is incorrect"
|
||||
Expect.equal posts[1].Id something "Page 1, post 2 is incorrect"
|
||||
Expect.equal posts[2].Id episode2 "Page 1, post 3 is incorrect"
|
||||
ensureNoText posts
|
||||
ensureEmpty posts
|
||||
let! posts = data.Post.FindPageOfPosts rootId 2 2
|
||||
Expect.hasLength posts 3 "There should have been 3 posts returned for page 2"
|
||||
Expect.equal posts[0].Id episode2 "Page 2, post 1 is incorrect"
|
||||
Expect.equal posts[1].Id episode1 "Page 2, post 2 is incorrect"
|
||||
Expect.equal posts[2].Id testPost1 "Page 2, post 3 is incorrect"
|
||||
ensureNoText posts
|
||||
ensureEmpty posts
|
||||
let! posts = data.Post.FindPageOfPosts rootId 3 2
|
||||
Expect.hasLength posts 1 "There should have been 1 post returned for page 3"
|
||||
Expect.equal posts[0].Id testPost1 "Page 3, post 1 is incorrect"
|
||||
ensureNoText posts
|
||||
ensureEmpty posts
|
||||
}
|
||||
|
||||
let ``FindPageOfPosts succeeds when finding a too-high page number`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfPosts rootId 88 3
|
||||
Expect.isEmpty posts "There should have been no posts returned (not enough posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfPosts succeeds when there are no posts`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfPosts (WebLogId "no-posts") 1 25
|
||||
Expect.isEmpty posts "There should have been no posts returned (no posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfPublishedPosts succeeds when posts are found`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfPublishedPosts rootId 1 3
|
||||
Expect.hasLength posts 4 "There should have been 4 posts returned for page 1"
|
||||
Expect.equal posts[0].Id something "Page 1, post 1 is incorrect"
|
||||
Expect.equal posts[1].Id episode2 "Page 1, post 2 is incorrect"
|
||||
Expect.equal posts[2].Id episode1 "Page 1, post 3 is incorrect"
|
||||
Expect.equal posts[3].Id testPost1 "Page 1, post 4 is incorrect"
|
||||
ensureHasText posts
|
||||
ensureEmpty posts
|
||||
let! posts = data.Post.FindPageOfPublishedPosts rootId 2 2
|
||||
Expect.hasLength posts 2 "There should have been 2 posts returned for page 2"
|
||||
Expect.equal posts[0].Id episode1 "Page 2, post 1 is incorrect"
|
||||
Expect.equal posts[1].Id testPost1 "Page 2, post 2 is incorrect"
|
||||
ensureHasText posts
|
||||
ensureEmpty posts
|
||||
}
|
||||
|
||||
let ``FindPageOfPublishedPosts succeeds when finding a too-high page number`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfPublishedPosts rootId 7 22
|
||||
Expect.isEmpty posts "There should have been no posts returned (not enough posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfPublishedPosts succeeds when there are no posts`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfPublishedPosts (WebLogId "empty") 1 8
|
||||
Expect.isEmpty posts "There should have been no posts returned (no posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfTaggedPosts succeeds when posts are found`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfTaggedPosts rootId "f#" 1 1
|
||||
Expect.hasLength posts 2 "There should have been 2 posts returned"
|
||||
Expect.equal posts[0].Id something "Page 1, post 1 is incorrect"
|
||||
Expect.equal posts[1].Id testPost1 "Page 1, post 2 is incorrect"
|
||||
ensureHasText posts
|
||||
ensureEmpty posts
|
||||
let! posts = data.Post.FindPageOfTaggedPosts rootId "f#" 2 1
|
||||
Expect.hasLength posts 1 "There should have been 1 posts returned"
|
||||
Expect.equal posts[0].Id testPost1 "Page 2, post 1 is incorrect"
|
||||
ensureHasText posts
|
||||
ensureEmpty posts
|
||||
}
|
||||
|
||||
let ``FindPageOfTaggedPosts succeeds when posts are found (excluding drafts)`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfTaggedPosts rootId "speculation" 1 10
|
||||
Expect.hasLength posts 1 "There should have been 1 post returned"
|
||||
Expect.equal posts[0].Id something "Post 1 is incorrect"
|
||||
ensureHasText posts
|
||||
ensureEmpty posts
|
||||
}
|
||||
|
||||
let ``FindPageOfTaggedPosts succeeds when finding a too-high page number`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfTaggedPosts rootId "f#" 436 18
|
||||
Expect.isEmpty posts "There should have been no posts returned (not enough posts)"
|
||||
}
|
||||
|
||||
let ``FindPageOfTaggedPosts succeeds when there are no posts`` (data: IData) = task {
|
||||
let! posts = data.Post.FindPageOfTaggedPosts rootId "non-existent-tag" 1 8
|
||||
Expect.isEmpty posts "There should have been no posts returned (no posts)"
|
||||
}
|
||||
|
||||
let ``FindSurroundingPosts succeeds when there is no next newer post`` (data: IData) = task {
|
||||
let! older, newer = data.Post.FindSurroundingPosts rootId somethingPublished
|
||||
Expect.isSome older "There should have been an older post"
|
||||
Expect.equal older.Value.Id episode2 "The next older post is incorrect"
|
||||
ensureHasText [ older.Value ]
|
||||
ensureEmpty [ older.Value ]
|
||||
Expect.isNone newer "There should not have been a newer post"
|
||||
}
|
||||
|
||||
let ``FindSurroundingPosts succeeds when there is no next older post`` (data: IData) = task {
|
||||
let! older, newer = data.Post.FindSurroundingPosts rootId testPost1Published
|
||||
Expect.isNone older "There should not have been an older post"
|
||||
Expect.isSome newer "There should have been a newer post"
|
||||
Expect.equal newer.Value.Id episode1 "The next newer post is incorrect"
|
||||
ensureHasText [ newer.Value ]
|
||||
ensureEmpty [ newer.Value ]
|
||||
}
|
||||
|
||||
let ``FindSurroundingPosts succeeds when older and newer exist`` (data: IData) = task {
|
||||
let! older, newer = data.Post.FindSurroundingPosts rootId episode1Published
|
||||
Expect.isSome older "There should have been an older post"
|
||||
Expect.equal older.Value.Id testPost1 "The next older post is incorrect"
|
||||
Expect.isSome newer "There should have been a newer post"
|
||||
Expect.equal newer.Value.Id episode2 "The next newer post is incorrect"
|
||||
ensureHasText [ older.Value; newer.Value ]
|
||||
ensureEmpty [ older.Value; newer.Value ]
|
||||
}
|
||||
|
||||
let ``Update succeeds when the post exists`` (data: IData) = task {
|
||||
let! before = data.Post.FindFullById (PostId "a-new-post") (WebLogId "test")
|
||||
Expect.isSome before "The post to be updated should have been found"
|
||||
do! data.Post.Update
|
||||
{ before.Value with
|
||||
AuthorId = WebLogUserId "someone-else"
|
||||
Status = Draft
|
||||
Title = "An Updated Test Post"
|
||||
Permalink = Permalink "2021/updated-post.html"
|
||||
PublishedOn = None
|
||||
UpdatedOn = Noda.epoch + Duration.FromDays 4
|
||||
Template = Some "other"
|
||||
Text = "<p>Updated text here"
|
||||
CategoryIds = [ CategoryId "c"; CategoryId "d"; CategoryId "e" ]
|
||||
Tags = [ "alpha"; "beta"; "nu"; "zeta" ]
|
||||
Episode = None
|
||||
Metadata = [ { Name = "Howdy"; Value = "Pardner" } ]
|
||||
PriorPermalinks = Permalink "2020/test-post.html" :: before.Value.PriorPermalinks
|
||||
Revisions =
|
||||
{ AsOf = Noda.epoch + Duration.FromDays 4; Text = Html "<p>Updated text here" }
|
||||
:: before.Value.Revisions }
|
||||
let! after = data.Post.FindFullById (PostId "a-new-post") (WebLogId "test")
|
||||
Expect.isSome after "The updated post should have been found"
|
||||
let post = after.Value
|
||||
Expect.equal post.AuthorId (WebLogUserId "someone-else") "Updated author is incorrect"
|
||||
Expect.equal post.Status Draft "Updated status is incorrect"
|
||||
Expect.equal post.Title "An Updated Test Post" "Updated title is incorrect"
|
||||
Expect.equal post.Permalink (Permalink "2021/updated-post.html") "Updated permalink is incorrect"
|
||||
Expect.isNone post.PublishedOn "Updated post should not have had a published-on date/time"
|
||||
Expect.equal post.UpdatedOn (Noda.epoch + Duration.FromDays 4) "Updated updated-on date/time is incorrect"
|
||||
Expect.equal post.Template (Some "other") "Updated template is incorrect"
|
||||
Expect.equal post.Text "<p>Updated text here" "Updated text is incorrect"
|
||||
Expect.equal
|
||||
post.CategoryIds [ CategoryId "c"; CategoryId "d"; CategoryId "e" ] "Updated category IDs are incorrect"
|
||||
Expect.equal post.Tags [ "alpha"; "beta"; "nu"; "zeta" ] "Updated tags are incorrect"
|
||||
Expect.isNone post.Episode "Update episode is incorrect"
|
||||
Expect.equal post.Metadata [ { Name = "Howdy"; Value = "Pardner" } ] "Updated metadata is incorrect"
|
||||
Expect.equal
|
||||
post.PriorPermalinks
|
||||
[ Permalink "2020/test-post.html"; Permalink "2020/test-post-a.html" ]
|
||||
"Updated prior permalinks are incorrect"
|
||||
Expect.equal
|
||||
post.Revisions
|
||||
[ { AsOf = Noda.epoch + Duration.FromDays 4; Text = Html "<p>Updated text here" }
|
||||
{ AsOf = Noda.epoch + Duration.FromMinutes 1L; Text = Html "<p>Test text here" } ]
|
||||
"Updated revisions are incorrect"
|
||||
}
|
||||
|
||||
let ``Update succeeds when the post does not exist`` (data: IData) = task {
|
||||
let postId = PostId "lost-post"
|
||||
do! data.Post.Update { Post.Empty with Id = postId; WebLogId = rootId }
|
||||
let! post = data.Post.FindById postId rootId
|
||||
Expect.isNone post "A post should not have been retrieved"
|
||||
}
|
||||
|
||||
let ``UpdatePriorPermalinks succeeds when the post exists`` (data: IData) = task {
|
||||
let links = [ Permalink "2024/ep-1.html"; Permalink "2023/ep-1.html" ]
|
||||
let! found = data.Post.UpdatePriorPermalinks episode1 rootId links
|
||||
Expect.isTrue found "The permalinks should have been updated"
|
||||
let! post = data.Post.FindFullById episode1 rootId
|
||||
Expect.isSome post "The post should have been found"
|
||||
Expect.equal post.Value.PriorPermalinks links "The prior permalinks were not correct"
|
||||
}
|
||||
|
||||
let ``UpdatePriorPermalinks succeeds when the post does not exist`` (data: IData) = task {
|
||||
let! found =
|
||||
data.Post.UpdatePriorPermalinks (PostId "silence") WebLogId.Empty [ Permalink "a.html"; Permalink "b.html" ]
|
||||
Expect.isFalse found "The permalinks should not have been updated"
|
||||
}
|
||||
|
||||
let ``Delete succeeds when a post is deleted`` (data: IData) = task {
|
||||
let! deleted = data.Post.Delete episode2 rootId
|
||||
Expect.isTrue deleted "The post should have been deleted"
|
||||
}
|
||||
|
||||
let ``Delete succeeds when a post is not deleted`` (data: IData) = task {
|
||||
let! deleted = data.Post.Delete episode2 rootId // this was deleted above
|
||||
Expect.isFalse deleted "A post should not have been deleted"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
module PostgresDataTests
|
||||
|
||||
open System
|
||||
open BitBadger.Documents
|
||||
open Expecto
|
||||
open Microsoft.Extensions.Logging.Abstractions
|
||||
|
@ -275,6 +274,88 @@ let postTests = testList "Post" [
|
|||
do! PostDataTests.``FindFullByWebLog succeeds when posts are not found`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "FindPageOfCategorizedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when posts are found`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when finding a too-high page number`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when a category has no posts" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when a category has no posts`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when posts are found`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when finding a too-high page number`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when there are no posts`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPublishedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when posts are found`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when finding a too-high page number`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when there are no posts`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "FindPageOfTaggedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when posts are found (excluding drafts)" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found (excluding drafts)`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when finding a too-high page number`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when there are no posts`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "FindSurroundingPosts" [
|
||||
testTask "succeeds when there is no next newer post" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when there is no next newer post`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when there is no next older post" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when there is no next older post`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when older and newer exist" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when older and newer exist`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "Update" [
|
||||
testTask "succeeds when the post exists" {
|
||||
do! PostDataTests.``Update succeeds when the post exists`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
do! PostDataTests.``Update succeeds when the post does not exist`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "UpdatePriorPermalinks" [
|
||||
testTask "succeeds when the post exists" {
|
||||
do! PostDataTests.``UpdatePriorPermalinks succeeds when the post exists`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
do! PostDataTests.``UpdatePriorPermalinks succeeds when the post does not exist`` (mkData ())
|
||||
}
|
||||
]
|
||||
testList "Delete" [
|
||||
testTask "succeeds when a post is deleted" {
|
||||
do! PostDataTests.``Delete succeeds when a post is deleted`` (mkData ())
|
||||
}
|
||||
testTask "succeeds when a post is not deleted" {
|
||||
do! PostDataTests.``Delete succeeds when a post is not deleted`` (mkData ())
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
/// Drop the throwaway PostgreSQL database
|
||||
|
|
|
@ -274,6 +274,88 @@ let postTests = testList "Post" [
|
|||
do! PostDataTests.``FindFullByWebLog succeeds when posts are not found`` data.Value
|
||||
}
|
||||
]
|
||||
testList "FindPageOfCategorizedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when posts are found`` data.Value
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when finding a too-high page number`` data.Value
|
||||
}
|
||||
testTask "succeeds when a category has no posts" {
|
||||
do! PostDataTests.``FindPageOfCategorizedPosts succeeds when a category has no posts`` data.Value
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when posts are found`` data.Value
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when finding a too-high page number`` data.Value
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfPosts succeeds when there are no posts`` data.Value
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPublishedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when posts are found`` data.Value
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when finding a too-high page number`` data.Value
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfPublishedPosts succeeds when there are no posts`` data.Value
|
||||
}
|
||||
]
|
||||
testList "FindPageOfTaggedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found`` data.Value
|
||||
}
|
||||
testTask "succeeds when posts are found (excluding drafts)" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found (excluding drafts)`` data.Value
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when finding a too-high page number`` data.Value
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
do! PostDataTests.``FindPageOfTaggedPosts succeeds when there are no posts`` data.Value
|
||||
}
|
||||
]
|
||||
testList "FindSurroundingPosts" [
|
||||
testTask "succeeds when there is no next newer post" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when there is no next newer post`` data.Value
|
||||
}
|
||||
testTask "succeeds when there is no next older post" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when there is no next older post`` data.Value
|
||||
}
|
||||
testTask "succeeds when older and newer exist" {
|
||||
do! PostDataTests.``FindSurroundingPosts succeeds when older and newer exist`` data.Value
|
||||
}
|
||||
]
|
||||
testList "Update" [
|
||||
testTask "succeeds when the post exists" {
|
||||
do! PostDataTests.``Update succeeds when the post exists`` data.Value
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
do! PostDataTests.``Update succeeds when the post does not exist`` data.Value
|
||||
}
|
||||
]
|
||||
testList "UpdatePriorPermalinks" [
|
||||
testTask "succeeds when the post exists" {
|
||||
do! PostDataTests.``UpdatePriorPermalinks succeeds when the post exists`` data.Value
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
do! PostDataTests.``UpdatePriorPermalinks succeeds when the post does not exist`` data.Value
|
||||
}
|
||||
]
|
||||
testList "Delete" [
|
||||
testTask "succeeds when a post is deleted" {
|
||||
do! PostDataTests.``Delete succeeds when a post is deleted`` data.Value
|
||||
}
|
||||
testTask "succeeds when a post is not deleted" {
|
||||
do! PostDataTests.``Delete succeeds when a post is not deleted`` data.Value
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
/// Drop the throwaway RethinkDB database
|
||||
|
|
|
@ -390,6 +390,132 @@ let postTests = testList "Post" [
|
|||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "FindPageOfCategorizedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfCategorizedPosts succeeds when posts are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfCategorizedPosts succeeds when finding a too-high page number`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when a category has no posts" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfCategorizedPosts succeeds when a category has no posts`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPosts succeeds when posts are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPosts succeeds when finding a too-high page number`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPosts succeeds when there are no posts`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "FindPageOfPublishedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPublishedPosts succeeds when posts are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPublishedPosts succeeds when finding a too-high page number`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfPublishedPosts succeeds when there are no posts`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "FindPageOfTaggedPosts" [
|
||||
testTask "succeeds when posts are found" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when posts are found (excluding drafts)" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfTaggedPosts succeeds when posts are found (excluding drafts)`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when finding a too-high page number" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfTaggedPosts succeeds when finding a too-high page number`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when there are no posts" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindPageOfTaggedPosts succeeds when there are no posts`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "FindSurroundingPosts" [
|
||||
testTask "succeeds when there is no next newer post" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindSurroundingPosts succeeds when there is no next newer post`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when there is no next older post" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindSurroundingPosts succeeds when there is no next older post`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when older and newer exist" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``FindSurroundingPosts succeeds when older and newer exist`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "Update" [
|
||||
testTask "succeeds when the post exists" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``Update succeeds when the post exists`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``Update succeeds when the post does not exist`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "UpdatePriorPermalinks" [
|
||||
testTask "succeeds when the post exists" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``UpdatePriorPermalinks succeeds when the post exists`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when the post does not exist" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``UpdatePriorPermalinks succeeds when the post does not exist`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
testList "Delete" [
|
||||
testTask "succeeds when a post is deleted" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``Delete succeeds when a post is deleted`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "succeeds when a post is not deleted" {
|
||||
let data = mkData ()
|
||||
try do! PostDataTests.``Delete succeeds when a post is not deleted`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
/// Delete the SQLite database
|
||||
|
|
|
@ -333,13 +333,39 @@
|
|||
"speculation"
|
||||
],
|
||||
"Metadata": [],
|
||||
"PriorPermalinks": [],
|
||||
"PriorPermalinks": [
|
||||
"2024/some-thing.html"
|
||||
],
|
||||
"Revisions": [
|
||||
{
|
||||
"AsOf": "2024-01-20T22:32:59Z",
|
||||
"Text": "HTML: <h2>Hmm</h2>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "VweKbWQiOkqqrjEdgP9wwg",
|
||||
"WebLogId": "uSitJEuD3UyzWC9jgOHc8g",
|
||||
"AuthorId": "5EM2rimH9kONpmd2zQkiVA",
|
||||
"Status": "Draft",
|
||||
"Title": "An Incomplete Thought",
|
||||
"Permalink": "2024/still-cooking.html",
|
||||
"UpdatedOn": "2024-01-24T22:35:00Z",
|
||||
"Text": "<p>Think think think",
|
||||
"CategoryIds": [
|
||||
"jw6N69YtTEWVHAO33jHU-w"
|
||||
],
|
||||
"Tags": [
|
||||
"speculation"
|
||||
],
|
||||
"Metadata": [],
|
||||
"PriorPermalinks": [],
|
||||
"Revisions": [
|
||||
{
|
||||
"AsOf": "2024-01-24T22:35:00Z",
|
||||
"Text": "HTML: <p>Think think think"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Uploads": []
|
||||
|
|
Loading…
Reference in New Issue
Block a user