Posts with many categories now render
- Fixed a problem with the RethinkDB query that was assembling categories for a single post (yay, @1lann on Slack!) - Finished conversion of data access functions to use async CEs
This commit is contained in:
@@ -8,25 +8,31 @@ let private r = RethinkDb.Driver.RethinkDB.R
|
||||
/// Shorthand to select all published posts for a web log
|
||||
let private publishedPosts (webLogId : string)=
|
||||
r.Table(Table.Post)
|
||||
.GetAll(r.Array(webLogId, PostStatus.Published)).OptArg("index", "WebLogAndStatus")
|
||||
.GetAll(r.Array (webLogId, PostStatus.Published)).OptArg("index", "WebLogAndStatus")
|
||||
|
||||
/// Shorthand to sort posts by published date, slice for the given page, and return a list
|
||||
let private toPostList conn pageNbr nbrPerPage (filter : ReqlExpr) =
|
||||
filter
|
||||
.OrderBy(r.Desc("PublishedOn"))
|
||||
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
|
||||
.RunResultAsync<Post list>(conn)
|
||||
|> await
|
||||
async {
|
||||
return!
|
||||
filter
|
||||
.OrderBy(r.Desc "PublishedOn")
|
||||
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
|
||||
.RunResultAsync<Post list> conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Shorthand to get a newer or older post
|
||||
let private adjacentPost conn (post : Post) (theFilter : ReqlExpr -> obj) (sort : obj) =
|
||||
(publishedPosts post.WebLogId)
|
||||
.Filter(theFilter)
|
||||
.OrderBy(sort)
|
||||
.Limit(1)
|
||||
.RunResultAsync<Post list>(conn)
|
||||
|> await
|
||||
|> List.tryHead
|
||||
async {
|
||||
let! post =
|
||||
(publishedPosts post.WebLogId)
|
||||
.Filter(theFilter)
|
||||
.OrderBy(sort)
|
||||
.Limit(1)
|
||||
.RunResultAsync<Post list> conn
|
||||
return List.tryHead post
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Find a newer post
|
||||
let private newerPost conn post theFilter = adjacentPost conn post theFilter <| r.Asc "PublishedOn"
|
||||
@@ -42,141 +48,163 @@ let findPageOfPublishedPosts conn webLogId pageNbr nbrPerPage =
|
||||
/// Get a page of published posts assigned to a given category
|
||||
let findPageOfCategorizedPosts conn webLogId (categoryId : string) pageNbr nbrPerPage =
|
||||
(publishedPosts webLogId)
|
||||
.Filter(ReqlFunction1(fun p -> upcast p.["CategoryIds"].Contains(categoryId)))
|
||||
.Filter(ReqlFunction1 (fun p -> upcast p.["CategoryIds"].Contains categoryId))
|
||||
|> toPostList conn pageNbr nbrPerPage
|
||||
|
||||
/// Get a page of published posts tagged with a given tag
|
||||
let findPageOfTaggedPosts conn webLogId (tag : string) pageNbr nbrPerPage =
|
||||
(publishedPosts webLogId)
|
||||
.Filter(ReqlFunction1(fun p -> upcast p.["Tags"].Contains(tag)))
|
||||
.Filter(ReqlFunction1 (fun p -> upcast p.["Tags"].Contains tag))
|
||||
|> toPostList conn pageNbr nbrPerPage
|
||||
|
||||
/// Try to get the next newest post from the given post
|
||||
let tryFindNewerPost conn post = newerPost conn post (fun p -> upcast p.["PublishedOn"].Gt(post.PublishedOn))
|
||||
let tryFindNewerPost conn post = newerPost conn post (fun p -> upcast p.["PublishedOn"].Gt post.PublishedOn)
|
||||
|
||||
/// Try to get the next newest post assigned to the given category
|
||||
let tryFindNewerCategorizedPost conn (categoryId : string) post =
|
||||
newerPost conn post (fun p -> upcast p.["PublishedOn"].Gt(post.PublishedOn)
|
||||
.And(p.["CategoryIds"].Contains(categoryId)))
|
||||
.And(p.["CategoryIds"].Contains categoryId))
|
||||
|
||||
/// Try to get the next newest tagged post from the given tagged post
|
||||
let tryFindNewerTaggedPost conn (tag : string) post =
|
||||
newerPost conn post (fun p -> upcast p.["PublishedOn"].Gt(post.PublishedOn).And(p.["Tags"].Contains(tag)))
|
||||
newerPost conn post (fun p -> upcast p.["PublishedOn"].Gt(post.PublishedOn).And(p.["Tags"].Contains tag))
|
||||
|
||||
/// Try to get the next oldest post from the given post
|
||||
let tryFindOlderPost conn post = olderPost conn post (fun p -> upcast p.["PublishedOn"].Lt(post.PublishedOn))
|
||||
let tryFindOlderPost conn post = olderPost conn post (fun p -> upcast p.["PublishedOn"].Lt post.PublishedOn)
|
||||
|
||||
/// Try to get the next oldest post assigned to the given category
|
||||
let tryFindOlderCategorizedPost conn (categoryId : string) post =
|
||||
olderPost conn post (fun p -> upcast p.["PublishedOn"].Lt(post.PublishedOn)
|
||||
.And(p.["CategoryIds"].Contains(categoryId)))
|
||||
.And(p.["CategoryIds"].Contains categoryId))
|
||||
|
||||
/// Try to get the next oldest tagged post from the given tagged post
|
||||
let tryFindOlderTaggedPost conn (tag : string) post =
|
||||
olderPost conn post (fun p -> upcast p.["PublishedOn"].Lt(post.PublishedOn).And(p.["Tags"].Contains(tag)))
|
||||
olderPost conn post (fun p -> upcast p.["PublishedOn"].Lt(post.PublishedOn).And(p.["Tags"].Contains tag))
|
||||
|
||||
/// Get a page of all posts in all statuses
|
||||
let findPageOfAllPosts conn (webLogId : string) pageNbr nbrPerPage =
|
||||
// FIXME: sort unpublished posts by their last updated date
|
||||
r.Table(Table.Post)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.OrderBy(r.Desc("PublishedOn"))
|
||||
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
|
||||
.RunResultAsync<Post list>(conn)
|
||||
|> await
|
||||
async {
|
||||
return!
|
||||
r.Table(Table.Post)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.OrderBy(r.Desc "PublishedOn")
|
||||
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
|
||||
.RunResultAsync<Post list> conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Try to find a post by its Id and web log Id
|
||||
let tryFindPost conn webLogId postId : Post option =
|
||||
r.Table(Table.Post)
|
||||
.Get(postId)
|
||||
.Filter(ReqlFunction1(fun p -> upcast p.["WebLogId"].Eq(webLogId)))
|
||||
.RunResultAsync<Post>(conn)
|
||||
|> await
|
||||
|> box
|
||||
|> function null -> None | post -> Some <| unbox post
|
||||
async {
|
||||
let! p =
|
||||
r.Table(Table.Post)
|
||||
.Get(postId)
|
||||
.Filter(ReqlFunction1 (fun p -> upcast p.["WebLogId"].Eq webLogId))
|
||||
.RunResultAsync<Post> conn
|
||||
return match box p with null -> None | post -> Some <| unbox post
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Try to find a post by its permalink
|
||||
let tryFindPostByPermalink conn webLogId permalink =
|
||||
r.Table(Table.Post)
|
||||
.GetAll(r.Array(webLogId, permalink)).OptArg("index", "Permalink")
|
||||
.Filter(ReqlFunction1(fun p -> upcast p.["Status"].Eq(PostStatus.Published)))
|
||||
.Without("Revisions")
|
||||
.Merge(ReqlFunction1(fun p ->
|
||||
upcast r.HashMap("Categories", r.Table(Table.Category)
|
||||
.GetAll(p.["CategoryIds"])
|
||||
.Without("Children")
|
||||
.OrderBy("Name")
|
||||
.CoerceTo("array"))))
|
||||
.Merge(ReqlFunction1(fun p ->
|
||||
upcast r.HashMap("Comments", r.Table(Table.Comment)
|
||||
.GetAll(p.["id"]).OptArg("index", "PostId")
|
||||
.OrderBy("PostedOn")
|
||||
.CoerceTo("array"))))
|
||||
.RunResultAsync<Post list>(conn)
|
||||
|> await
|
||||
|> List.tryHead
|
||||
async {
|
||||
let! post =
|
||||
r.Table(Table.Post)
|
||||
.GetAll(r.Array (webLogId, permalink)).OptArg("index", "Permalink")
|
||||
.Filter(ReqlFunction1 (fun p -> upcast p.["Status"].Eq PostStatus.Published))
|
||||
.Without("Revisions")
|
||||
.Merge(ReqlFunction1 (fun p ->
|
||||
upcast r.HashMap(
|
||||
"Categories", r.Table(Table.Category)
|
||||
.GetAll(r.Args p.["CategoryIds"])
|
||||
.Without("Children")
|
||||
.OrderBy("Name")
|
||||
.CoerceTo("array")).With(
|
||||
"Comments", r.Table(Table.Comment)
|
||||
.GetAll(p.["id"]).OptArg("index", "PostId")
|
||||
.OrderBy("PostedOn")
|
||||
.CoerceTo("array"))))
|
||||
.RunResultAsync<Post list> conn
|
||||
return List.tryHead post
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Try to find a post by its prior permalink
|
||||
let tryFindPostByPriorPermalink conn (webLogId : string) (permalink : string) =
|
||||
r.Table(Table.Post)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.Filter(ReqlFunction1(fun p ->
|
||||
upcast p.["PriorPermalinks"].Contains(permalink).And(p.["Status"].Eq(PostStatus.Published))))
|
||||
.Without("Revisions")
|
||||
.RunResultAsync<Post list>(conn)
|
||||
|> await
|
||||
|> List.tryHead
|
||||
async {
|
||||
let! post =
|
||||
r.Table(Table.Post)
|
||||
.GetAll(webLogId).OptArg("index", "WebLogId")
|
||||
.Filter(ReqlFunction1 (fun p ->
|
||||
upcast p.["PriorPermalinks"].Contains(permalink).And(p.["Status"].Eq PostStatus.Published)))
|
||||
.Without("Revisions")
|
||||
.RunResultAsync<Post list> conn
|
||||
return List.tryHead post
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
/// Get a set of posts for RSS
|
||||
let findFeedPosts conn webLogId nbr : (Post * User option) list =
|
||||
let tryFindUser userId =
|
||||
async {
|
||||
let! u =
|
||||
r.Table(Table.User)
|
||||
.Get(userId)
|
||||
.RunAtomAsync<User> conn
|
||||
return match box u with null -> None | user -> Some <| unbox user
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
(publishedPosts webLogId)
|
||||
.Merge(ReqlFunction1(fun post ->
|
||||
upcast r.HashMap("Categories", r.Table(Table.Category)
|
||||
.GetAll(post.["CategoryIds"])
|
||||
.OrderBy("Name")
|
||||
.Pluck("id", "Name")
|
||||
.CoerceTo("array"))))
|
||||
.Merge(ReqlFunction1 (fun post ->
|
||||
upcast r.HashMap(
|
||||
"Categories", r.Table(Table.Category)
|
||||
.GetAll(r.Args post.["CategoryIds"])
|
||||
.OrderBy("Name")
|
||||
.Pluck("id", "Name")
|
||||
.CoerceTo("array"))))
|
||||
|> toPostList conn 1 nbr
|
||||
|> List.map (fun post -> post, r.Table(Table.User)
|
||||
.Get(post.AuthorId)
|
||||
.RunAtomAsync<User>(conn)
|
||||
|> await
|
||||
|> box
|
||||
|> function null -> None | user -> Some <| unbox user)
|
||||
|> List.map (fun post -> post, tryFindUser post.AuthorId)
|
||||
|
||||
/// Add a post
|
||||
let addPost conn post =
|
||||
r.Table(Table.Post)
|
||||
.Insert(post)
|
||||
.RunResultAsync(conn)
|
||||
|> await
|
||||
|> ignore
|
||||
async {
|
||||
do! r.Table(Table.Post)
|
||||
.Insert(post)
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> (Async.RunSynchronously >> ignore)
|
||||
|
||||
/// Update a post
|
||||
let updatePost conn (post : Post) =
|
||||
r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Replace( { post with Categories = []
|
||||
Comments = [] } )
|
||||
.RunResultAsync(conn)
|
||||
|> await
|
||||
|> ignore
|
||||
async {
|
||||
do! r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Replace( { post with Categories = []
|
||||
Comments = [] } )
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> (Async.RunSynchronously >> ignore)
|
||||
|
||||
/// Save a post
|
||||
let savePost conn (post : Post) =
|
||||
match post.Id with
|
||||
| "new" -> let newPost = { post with Id = string <| System.Guid.NewGuid() }
|
||||
r.Table(Table.Post)
|
||||
.Insert(newPost)
|
||||
.RunResultAsync(conn)
|
||||
|> await
|
||||
|> ignore
|
||||
newPost.Id
|
||||
| _ -> r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Replace( { post with Categories = []
|
||||
Comments = [] } )
|
||||
.RunResultAsync(conn)
|
||||
|> await
|
||||
|> ignore
|
||||
post.Id
|
||||
| "new" ->
|
||||
let newPost = { post with Id = string <| System.Guid.NewGuid() }
|
||||
async {
|
||||
do! r.Table(Table.Post)
|
||||
.Insert(newPost)
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
newPost.Id
|
||||
| _ ->
|
||||
async {
|
||||
do! r.Table(Table.Post)
|
||||
.Get(post.Id)
|
||||
.Replace( { post with Categories = []
|
||||
Comments = [] } )
|
||||
.RunResultAsync conn
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
post.Id
|
||||
|
||||
Reference in New Issue
Block a user