time sort in tree with replies #35

This commit is contained in:
Umputun
2018-05-16 01:08:36 -05:00
parent 369e4d8be7
commit 4cf7c0a5ee
2 changed files with 31 additions and 14 deletions
+24 -6
View File
@@ -3,6 +3,7 @@ package rest
import (
"sort"
"strings"
"time"
"github.com/umputun/remark/app/store"
)
@@ -16,6 +17,12 @@ type Tree struct {
type Node struct {
Comment store.Comment `json:"comment"`
Replies []*Node `json:"replies,omitempty"`
ts time.Time
}
// timeStamp wraps time.Time to simplify pointer ops
type timeStamp struct {
time.Time
}
// MakeTree gets unsorted list of comments and produces Tree
@@ -27,10 +34,12 @@ func MakeTree(comments []store.Comment, sortType string) *Tree {
for _, rootComment := range topComments {
node := Node{Comment: rootComment}
commentsTree := res.proc(comments, &node, rootComment.ID)
ts := timeStamp{}
commentsTree, t := res.proc(comments, &node, &ts, rootComment.ID)
if rootComment.Deleted && len(commentsTree.Replies) == 0 { // skip deleted with no subcomments
continue
}
commentsTree.ts = t
res.Nodes = append(res.Nodes, commentsTree)
}
@@ -39,18 +48,26 @@ func MakeTree(comments []store.Comment, sortType string) *Tree {
}
// proc makes tree for one top-level comment recursively
func (t *Tree) proc(comments []store.Comment, node *Node, parentID string) *Node {
func (t *Tree) proc(comments []store.Comment, node *Node, ts *timeStamp, parentID string) (*Node, time.Time) {
if ts.IsZero() {
ts.Time = node.Comment.Timestamp
}
repComments := t.filter(comments, parentID)
for _, rc := range repComments {
if rc.Timestamp.After(ts.Time) {
ts.Time = rc.Timestamp
}
rnode := &Node{Comment: rc, Replies: []*Node{}}
node.Replies = append(node.Replies, rnode)
t.proc(comments, rnode, rc.ID)
t.proc(comments, rnode, ts, rc.ID)
}
// replies always sorted by time
sort.Slice(node.Replies, func(i, j int) bool {
return node.Replies[i].Comment.Timestamp.Before(node.Replies[j].Comment.Timestamp)
})
return node
return node, ts.Time
}
// filter returns comments for parentID
@@ -65,15 +82,16 @@ func (t *Tree) filter(comments []store.Comment, parentID string) (f []store.Comm
}
// sort list of nodes, i.e. top-level comments
// time sort uses ts from latest reply
func (t *Tree) sortNodes(sortType string) {
sort.Slice(t.Nodes, func(i, j int) bool {
switch sortType {
case "+time", "-time", "time":
if strings.HasPrefix(sortType, "-") {
return t.Nodes[i].Comment.Timestamp.After(t.Nodes[j].Comment.Timestamp)
return t.Nodes[i].ts.After(t.Nodes[j].ts)
}
return t.Nodes[i].Comment.Timestamp.Before(t.Nodes[j].Comment.Timestamp)
return t.Nodes[i].ts.Before(t.Nodes[j].ts)
case "+score", "-score", "score":
if strings.HasPrefix(sortType, "-") {
+7 -8
View File
@@ -50,8 +50,8 @@ func TestTreeSortNodes(t *testing.T) {
{ID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 2, 0, time.UTC), Score: 3},
{ID: "11", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 11, 0, time.UTC)},
{ID: "13", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 13, 0, time.UTC)},
{ID: "12", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 12, 0, time.UTC)},
{ID: "131", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 46, 31, 0, time.UTC)},
{ID: "12", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 14, 0, time.UTC)},
{ID: "131", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 50, 31, 0, time.UTC)},
{ID: "132", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 46, 32, 0, time.UTC)},
{ID: "21", ParentID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 21, 0, time.UTC)},
{ID: "22", ParentID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 22, 0, time.UTC)},
@@ -61,14 +61,13 @@ func TestTreeSortNodes(t *testing.T) {
{ID: "5", Deleted: true},
}
res := MakeTree(comments, "time")
assert.Equal(t, "1", res.Nodes[0].Comment.ID)
res = MakeTree(comments, "time")
assert.Equal(t, "1", res.Nodes[0].Comment.ID)
res := MakeTree(comments, "+time")
assert.Equal(t, "2", res.Nodes[0].Comment.ID)
t.Log(res.Nodes[0].Comment.ID, res.Nodes[0].ts)
res = MakeTree(comments, "-time")
assert.Equal(t, "6", res.Nodes[0].Comment.ID)
t.Log(res.Nodes[0].Comment.ID, res.Nodes[0].ts)
assert.Equal(t, "1", res.Nodes[0].Comment.ID)
res = MakeTree(comments, "score")
assert.Equal(t, "4", res.Nodes[0].Comment.ID)