member_grouping.gno
4.10 Kb · 162 lines
1package commondao
2
3import (
4 "errors"
5
6 "gno.land/p/nt/avl/v0"
7)
8
9type (
10 // MemberGroupIterFn defines a callback to iterate DAO members groups.
11 MemberGroupIterFn func(MemberGroup) bool
12
13 // MemberGrouping defines an interface for storing multiple member groups.
14 // Member grouping can be used by implementations that require grouping users
15 // by roles or by tiers for example.
16 MemberGrouping interface {
17 // Size returns the number of groups that grouping contains.
18 Size() int
19
20 // Has checks if a group exists.
21 Has(name string) bool
22
23 // Add adds an new member group if it doesn't exists.
24 Add(name string) (MemberGroup, error)
25
26 // Get returns a member group.
27 Get(name string) (_ MemberGroup, found bool)
28
29 // Delete deletes a member group.
30 Delete(name string) error
31
32 // IterateByOffset iterates all member groups.
33 // The callback can return true to stop iteration.
34 IterateByOffset(offset, count int, fn MemberGroupIterFn) (stopped bool)
35 }
36)
37
38// NewMemberGrouping creates a new members grouping.
39func NewMemberGrouping(options ...MemberGroupingOption) MemberGrouping {
40 g := &memberGrouping{
41 createStorage: func(string) MemberStorage { return NewMemberStorage() },
42 }
43
44 for _, apply := range options {
45 apply(g)
46 }
47 return g
48}
49
50type memberGrouping struct {
51 groups avl.Tree // string(name) -> MemberGroup
52 createStorage func(group string) MemberStorage
53}
54
55// Size returns the number of groups that grouping contains.
56func (g memberGrouping) Size() int {
57 return g.groups.Size()
58}
59
60// Has checks if a group exists.
61func (g memberGrouping) Has(name string) bool {
62 return g.groups.Has(name)
63}
64
65// Add adds an new member group if it doesn't exists.
66func (g *memberGrouping) Add(name string) (MemberGroup, error) {
67 if g.groups.Has(name) {
68 return nil, errors.New("member group already exists: " + name)
69 }
70
71 mg, err := NewMemberGroup(name, g.createStorage(name))
72 if err != nil {
73 return nil, err
74 }
75
76 g.groups.Set(name, mg)
77 return mg, nil
78}
79
80// Get returns a member group.
81func (g memberGrouping) Get(name string) (_ MemberGroup, found bool) {
82 v, found := g.groups.Get(name)
83 if !found {
84 return nil, false
85 }
86 return v.(MemberGroup), true
87}
88
89// Delete deletes a member group.
90func (g *memberGrouping) Delete(name string) error {
91 g.groups.Remove(name)
92 return nil
93}
94
95// IterateByOffset iterates all member groups.
96func (g memberGrouping) IterateByOffset(offset, count int, fn MemberGroupIterFn) bool {
97 return g.groups.IterateByOffset(offset, count, func(_ string, v any) bool {
98 return fn(v.(MemberGroup))
99 })
100}
101
102// NewReadonlyMemberGrouping creates a new grouping if member.
103func NewReadonlyMemberGrouping(g MemberGrouping) (*ReadonlyMemberGrouping, error) {
104 if g == nil {
105 return nil, errors.New("member grouping is required")
106 }
107 return &ReadonlyMemberGrouping{g}, nil
108}
109
110// MustNewReadonlyMemberGrouping creates a new grouping if member or panics on error.
111func MustNewReadonlyMemberGrouping(g MemberGrouping) *ReadonlyMemberGrouping {
112 grouping, err := NewReadonlyMemberGrouping(g)
113 if err != nil {
114 panic(err)
115 }
116 return grouping
117}
118
119// ReadonlyMemberGrouping defines a type for storing multiple readonly member groups.
120type ReadonlyMemberGrouping struct {
121 grouping MemberGrouping
122}
123
124// Size returns the number of groups that grouping contains.
125func (g ReadonlyMemberGrouping) Size() int {
126 if g.grouping == nil {
127 return 0
128 }
129 return g.grouping.Size()
130}
131
132// Has checks if a group exists.
133func (g ReadonlyMemberGrouping) Has(name string) bool {
134 if g.grouping == nil {
135 return false
136 }
137 return g.grouping.Has(name)
138}
139
140// Get returns a member group.
141func (g ReadonlyMemberGrouping) Get(name string) (_ *ReadonlyMemberGroup, found bool) {
142 if g.grouping == nil {
143 return nil, false
144 }
145
146 group, found := g.grouping.Get(name)
147 if !found {
148 return nil, false
149 }
150 return MustNewReadonlyMemberGroup(group), true
151}
152
153// IterateByOffset iterates all member groups.
154func (g ReadonlyMemberGrouping) IterateByOffset(offset, count int, fn func(*ReadonlyMemberGroup) bool) bool {
155 if g.grouping == nil {
156 return false
157 }
158
159 return g.grouping.IterateByOffset(offset, count, func(group MemberGroup) bool {
160 return fn(MustNewReadonlyMemberGroup(group))
161 })
162}