post_storage.gno
2.23 Kb · 97 lines
1package boards
2
3import (
4 "errors"
5
6 "gno.land/p/nt/avl/v0"
7)
8
9type (
10 // PostIterFn defines a function type to iterate posts.
11 PostIterFn func(*Post) bool
12
13 // PostStorage defines an interface for posts storage.
14 PostStorage interface {
15 // Get retruns a post that matches an ID.
16 Get(ID) (_ *Post, found bool)
17
18 // Remove removes a post from the storage.
19 Remove(ID) (_ *Post, removed bool)
20
21 // Add adds a post in the storage.
22 Add(*Post) error
23
24 // Size returns the number of posts in the storage.
25 Size() int
26
27 // Iterate iterates posts.
28 // To reverse iterate posts use a negative count.
29 // If the callback returns true, the iteration is stopped.
30 Iterate(start, count int, fn PostIterFn) bool
31 }
32)
33
34// NewPostStorage creates a new storage for posts.
35// The new storage uses an AVL tree to store posts.
36func NewPostStorage() PostStorage {
37 return &postStorage{avl.NewTree()}
38}
39
40type postStorage struct {
41 posts *avl.Tree // string(Post.ID) -> *Post
42}
43
44// Get retruns a post that matches an ID.
45func (s postStorage) Get(id ID) (*Post, bool) {
46 k := makePostKey(id)
47 v, found := s.posts.Get(k)
48 if !found {
49 return nil, false
50 }
51 return v.(*Post), true
52}
53
54// Remove removes a post from the storage.
55func (s *postStorage) Remove(id ID) (*Post, bool) {
56 k := makePostKey(id)
57 v, removed := s.posts.Remove(k)
58 if !removed {
59 return nil, false
60 }
61 return v.(*Post), true
62}
63
64// Add adds a post in the storage.
65// It updates existing posts when storage contains one with the same ID.
66func (s *postStorage) Add(p *Post) error {
67 if p == nil {
68 return errors.New("saving nil posts is not allowed")
69 }
70
71 s.posts.Set(makePostKey(p.ID), p)
72 return nil
73}
74
75// Size returns the number of posts in the storage.
76func (s postStorage) Size() int {
77 return s.posts.Size()
78}
79
80// Iterate iterates posts.
81// To reverse iterate posts use a negative count.
82// If the callback returns true, the iteration is stopped.
83func (s postStorage) Iterate(start, count int, fn PostIterFn) bool {
84 if count < 0 {
85 return s.posts.ReverseIterateByOffset(start, -count, func(_ string, v any) bool {
86 return fn(v.(*Post))
87 })
88 }
89
90 return s.posts.IterateByOffset(start, count, func(_ string, v any) bool {
91 return fn(v.(*Post))
92 })
93}
94
95func makePostKey(postID ID) string {
96 return postID.PaddedString()
97}