entry.gno
2.70 Kb · 148 lines
1package collection
2
3import "gno.land/p/nt/ufmt/v0"
4
5// Entry represents a single object in the collection with its ID
6type Entry struct {
7 ID string
8 Obj any
9}
10
11// String returns a string representation of the Entry
12func (e *Entry) String() string {
13 if e == nil {
14 return "<nil>"
15 }
16 return ufmt.Sprintf("Entry{ID: %s, Obj: %v}", e.ID, e.Obj)
17}
18
19// EntryIterator provides iteration over collection entries
20type EntryIterator struct {
21 collection *Collection
22 indexName string
23 key string
24 currentID string
25 currentObj any
26 err error
27 closed bool
28
29 // For multi-value cases
30 ids []string
31 currentIdx int
32}
33
34func (ei *EntryIterator) Close() error {
35 ei.closed = true
36 ei.currentID = ""
37 ei.currentObj = nil
38 ei.ids = nil
39 return nil
40}
41
42func (ei *EntryIterator) Next() bool {
43 if ei == nil || ei.closed || ei.err != nil {
44 return false
45 }
46
47 // Handle ID index specially
48 if ei.indexName == IDIndex {
49 if ei.currentID != "" { // We've already returned the single value
50 return false
51 }
52 obj := ei.collection.indexes[IDIndex].tree.Get(ei.key)
53 if obj == nil {
54 return false
55 }
56 ei.currentID = ei.key
57 ei.currentObj = obj
58 return true
59 }
60
61 // Get the index
62 idx, exists := ei.collection.indexes[ei.indexName]
63 if !exists {
64 return false
65 }
66
67 // Initialize ids slice if needed
68 if ei.ids == nil {
69 idData := idx.tree.Get(ei.key)
70 if idData == nil {
71 return false
72 }
73
74 switch stored := idData.(type) {
75 case []string:
76 ei.ids = stored
77 ei.currentIdx = -1
78 case string:
79 ei.ids = []string{stored}
80 ei.currentIdx = -1
81 default:
82 return false
83 }
84 }
85
86 // Move to next ID
87 ei.currentIdx++
88 if ei.currentIdx >= len(ei.ids) {
89 return false
90 }
91
92 // Fetch the actual object
93 ei.currentID = ei.ids[ei.currentIdx]
94 obj := ei.collection.indexes[IDIndex].tree.Get(ei.currentID)
95 if obj == nil {
96 // Skip invalid entries
97 return ei.Next()
98 }
99 ei.currentObj = obj
100 return true
101}
102
103func (ei *EntryIterator) Error() error {
104 return ei.err
105}
106
107func (ei *EntryIterator) Value() *Entry {
108 if ei == nil || ei.closed || ei.currentID == "" {
109 return nil
110 }
111 return &Entry{
112 ID: ei.currentID,
113 Obj: ei.currentObj,
114 }
115}
116
117func (ei *EntryIterator) Empty() bool {
118 if ei == nil || ei.closed || ei.err != nil {
119 return true
120 }
121
122 // Handle ID index specially
123 if ei.indexName == IDIndex {
124 return !ei.collection.indexes[IDIndex].tree.Has(ei.key)
125 }
126
127 // Get the index
128 idx, exists := ei.collection.indexes[ei.indexName]
129 if !exists {
130 return true
131 }
132
133 // Check if key exists in index
134 idData := idx.tree.Get(ei.key)
135 if idData == nil {
136 return true
137 }
138
139 // Check if there are any valid IDs
140 switch stored := idData.(type) {
141 case []string:
142 return len(stored) == 0
143 case string:
144 return stored == ""
145 default:
146 return true
147 }
148}