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}