Search Apps Documentation Source Content File Folder Download Copy Actions Download

replies_storage.gno

2.33 Kb ยท 93 lines
 1package boards2
 2
 3import (
 4	"errors"
 5
 6	"gno.land/p/gnoland/boards"
 7	"gno.land/p/nt/avl"
 8)
 9
10// NewReplyStorage creates a new storage for thread replies.
11// This is a customized post storage that also keeps a flat index with all replies
12// that exists within a thread, which allows to get any reply from their thread.
13func NewReplyStorage() boards.PostStorage {
14	return &replyStorage{
15		PostStorage: boards.NewPostStorage(),
16		all:         avl.NewTree(),
17	}
18}
19
20type replyStorage struct {
21	boards.PostStorage
22
23	// Flat index to store all replies that exists within a thread
24	all *avl.Tree // string(Post.ID) -> *Post
25}
26
27// Get retruns a reply that matches an ID.
28// Reply can be a direct thread reply or a sub-reply.
29func (s replyStorage) Get(id boards.ID) (*boards.Post, bool) {
30	post, found := s.PostStorage.Get(id)
31	if found {
32		return post, true
33	}
34
35	k := makeReplyKey(id)
36	v, found := s.all.Get(k)
37	if !found {
38		return nil, false
39	}
40	return v.(*boards.Post), true
41}
42
43// Remove removes a post from the storage.
44func (s *replyStorage) Remove(id boards.ID) (*boards.Post, bool) {
45	post, removed := s.PostStorage.Remove(id)
46	if removed {
47		return post, true
48	}
49
50	// When reply is not a direct thread reply try to remove it from the flat index
51	k := makeReplyKey(id)
52	v, removed := s.all.Remove(k)
53	if !removed {
54		return nil, false
55	}
56	return v.(*boards.Post), true
57}
58
59// Add adds a post in the storage.
60// It updates existing posts when storage contains one with the same ID.
61func (s *replyStorage) Add(p *boards.Post) error {
62	if p == nil {
63		return errors.New("saving nil replies is not allowed")
64	}
65
66	// If post is a direct thread child add it to the post storage
67	if p.ParentID == p.ThreadID {
68		return s.PostStorage.Add(p)
69	}
70
71	// Otherwise when post is a sub-reply add it to the flat index
72	k := makeReplyKey(p.ID)
73	s.all.Set(k, p)
74	return nil
75}
76
77// Size returns the number of direct replies in the storage.
78// It doesn't includes sub-replies.
79func (s replyStorage) Size() int {
80	return s.PostStorage.Size()
81}
82
83// Iterate iterates direct replies.
84// To reverse iterate posts use a negative count.
85// If the callback returns true, the iteration is stopped.
86// Sub-replies are NOT iterated.
87func (s replyStorage) Iterate(start, count int, fn boards.PostIterFn) bool {
88	return s.PostStorage.Iterate(start, count, fn)
89}
90
91func makeReplyKey(id boards.ID) string {
92	return id.Key()
93}