Search Apps Documentation Source Content File Folder Download Copy Actions Download

member_storage.gno

4.84 Kb · 174 lines
  1package commondao
  2
  3import (
  4	"errors"
  5
  6	"gno.land/p/moul/addrset"
  7)
  8
  9type (
 10	// MemberIterFn defines a callback to iterate DAO members.
 11	MemberIterFn func(address) bool
 12
 13	// MemberStorage defines an interface for member storages.
 14	MemberStorage interface {
 15		// Size returns the number of members in the storage.
 16		Size() int
 17
 18		// Has checks if a member exists in the storage.
 19		Has(address) bool
 20
 21		// Add adds a member to the storage.
 22		// Returns true if the member is added, or false if it already existed.
 23		Add(address) bool
 24
 25		// Remove removes a member from the storage.
 26		// Returns true if member was removed, or false if it was not found.
 27		Remove(address) bool
 28
 29		// Grouping returns member groups when supported.
 30		// When nil is returned it means that grouping of members is not supported.
 31		// Member groups can be used by implementations that require grouping users
 32		// by roles or by tiers for example.
 33		Grouping() MemberGrouping
 34
 35		// IterateByOffset iterates members starting at the given offset.
 36		// The callback can return true to stop iteration.
 37		IterateByOffset(offset, count int, fn MemberIterFn) (stopped bool)
 38	}
 39)
 40
 41// NewMemberStorage creates a new member storage.
 42// Function returns a new member storage that doesn't support member groups.
 43// This type of storage is useful when there is no need to group members.
 44func NewMemberStorage() MemberStorage {
 45	return &memberStorage{}
 46}
 47
 48// NewMemberStorageWithGrouping a new member storage with support for member groups.
 49// Member groups can be used by implementations that require grouping users by roles
 50// or by tiers for example.
 51func NewMemberStorageWithGrouping(options ...MemberGroupingOption) MemberStorage {
 52	return &memberStorage{grouping: NewMemberGrouping(options...)}
 53}
 54
 55type memberStorage struct {
 56	addrset.Set
 57
 58	grouping MemberGrouping
 59}
 60
 61// Size returns the number of members in the storage.
 62// The result is the number of members within the base underlying storage,
 63// grouped members are not included, they must be counted separately.
 64func (s memberStorage) Size() int {
 65	return s.Set.Size()
 66}
 67
 68// Has checks if a member exists in the storage.
 69// Member is also searched within all defined member groups.
 70func (s memberStorage) Has(member address) bool {
 71	// Check underlying member address storage
 72	if s.Set.Has(member) {
 73		return true
 74	}
 75
 76	if s.grouping == nil {
 77		return false
 78	}
 79
 80	// Check groups when member is not found in underlying storage
 81	return s.grouping.IterateByOffset(0, s.grouping.Size(), func(g MemberGroup) bool {
 82		return g.Members().Has(member)
 83	})
 84}
 85
 86// Grouping returns member groups.
 87func (s memberStorage) Grouping() MemberGrouping {
 88	return s.grouping
 89}
 90
 91// IterateByOffset iterates members starting at the given offset.
 92// The callback can return true to stop iteration.
 93func (s memberStorage) IterateByOffset(offset, count int, fn MemberIterFn) bool {
 94	var stopped bool
 95	s.Set.IterateByOffset(offset, count, func(member address) bool {
 96		stopped = fn(member)
 97		return stopped
 98	})
 99	return stopped
100}
101
102// NewReadonlyMemberStorage creates a new readonly member storage.
103func NewReadonlyMemberStorage(s MemberStorage) (*ReadonlyMemberStorage, error) {
104	if s == nil {
105		return nil, errors.New("member storage is required")
106	}
107	return &ReadonlyMemberStorage{s}, nil
108}
109
110// MustNewReadonlyMemberStorage creates a new readonly member storage or panics on error.
111func MustNewReadonlyMemberStorage(s MemberStorage) *ReadonlyMemberStorage {
112	storage, err := NewReadonlyMemberStorage(s)
113	if err != nil {
114		panic(err)
115	}
116	return storage
117}
118
119// ReadonlyMemberStorage defines a readonly member storage.
120type ReadonlyMemberStorage struct {
121	storage MemberStorage
122}
123
124// Size returns the number of members in the storage.
125func (s ReadonlyMemberStorage) Size() int {
126	if s.storage == nil {
127		return 0
128	}
129	return s.storage.Size()
130}
131
132// Has checks if a member exists in the storage.
133func (s ReadonlyMemberStorage) Has(member address) bool {
134	if s.storage == nil {
135		return false
136	}
137	return s.storage.Has(member)
138}
139
140// Grouping returns member groups.
141func (s ReadonlyMemberStorage) Grouping() *ReadonlyMemberGrouping {
142	if s.storage == nil {
143		return nil
144	}
145
146	if g := s.storage.Grouping(); g != nil {
147		return MustNewReadonlyMemberGrouping(g)
148	}
149	return nil
150}
151
152// IterateByOffset iterates members starting at the given offset.
153// The callback can return true to stop iteration.
154func (s ReadonlyMemberStorage) IterateByOffset(offset, count int, fn MemberIterFn) bool {
155	if s.storage != nil {
156		return s.storage.IterateByOffset(offset, count, fn)
157	}
158	return false
159}
160
161// CountStorageMembers returns the total number of members in the storage.
162// It counts all members in each group and the ones without group.
163func CountStorageMembers(s *ReadonlyMemberStorage) int {
164	if s == nil {
165		return 0
166	}
167
168	c := s.Size()
169	s.Grouping().IterateByOffset(0, s.Grouping().Size(), func(g *ReadonlyMemberGroup) bool {
170		c += g.Members().Size()
171		return false
172	})
173	return c
174}