fetch-event.go raw
1 package neo4j
2
3 import (
4 "context"
5 "fmt"
6
7 "next.orly.dev/pkg/database"
8 "next.orly.dev/pkg/database/indexes/types"
9 "next.orly.dev/pkg/nostr/encoders/event"
10 "next.orly.dev/pkg/nostr/encoders/hex"
11 "next.orly.dev/pkg/nostr/encoders/tag"
12 "next.orly.dev/pkg/interfaces/store"
13 )
14
15 // FetchEventBySerial retrieves an event by its serial number
16 func (n *N) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error) {
17 serial := ser.Get()
18
19 cypher := `
20 MATCH (e:Event {serial: $serial})
21 RETURN e.id AS id,
22 e.kind AS kind,
23 e.created_at AS created_at,
24 e.content AS content,
25 e.sig AS sig,
26 e.pubkey AS pubkey,
27 e.tags AS tags`
28
29 params := map[string]any{"serial": int64(serial)}
30
31 result, err := n.ExecuteRead(context.Background(), cypher, params)
32 if err != nil {
33 return nil, fmt.Errorf("failed to fetch event by serial: %w", err)
34 }
35
36 evs, err := n.parseEventsFromResult(result)
37 if err != nil {
38 return nil, err
39 }
40
41 if len(evs) == 0 {
42 return nil, fmt.Errorf("event not found")
43 }
44
45 return evs[0], nil
46 }
47
48 // FetchEventsBySerials retrieves multiple events by their serial numbers
49 func (n *N) FetchEventsBySerials(serials []*types.Uint40) (
50 events map[uint64]*event.E, err error,
51 ) {
52 if len(serials) == 0 {
53 return make(map[uint64]*event.E), nil
54 }
55
56 // Build list of serial numbers
57 serialNums := make([]int64, len(serials))
58 for i, ser := range serials {
59 serialNums[i] = int64(ser.Get())
60 }
61
62 cypher := `
63 MATCH (e:Event)
64 WHERE e.serial IN $serials
65 RETURN e.id AS id,
66 e.kind AS kind,
67 e.created_at AS created_at,
68 e.content AS content,
69 e.sig AS sig,
70 e.pubkey AS pubkey,
71 e.tags AS tags,
72 e.serial AS serial`
73
74 params := map[string]any{"serials": serialNums}
75
76 result, err := n.ExecuteRead(context.Background(), cypher, params)
77 if err != nil {
78 return nil, fmt.Errorf("failed to fetch events by serials: %w", err)
79 }
80
81 // Parse events and map by serial
82 events = make(map[uint64]*event.E)
83 ctx := context.Background()
84
85 for result.Next(ctx) {
86 record := result.Record()
87 if record == nil {
88 continue
89 }
90
91 // Parse event
92 idRaw, _ := record.Get("id")
93 kindRaw, _ := record.Get("kind")
94 createdAtRaw, _ := record.Get("created_at")
95 contentRaw, _ := record.Get("content")
96 sigRaw, _ := record.Get("sig")
97 pubkeyRaw, _ := record.Get("pubkey")
98 tagsRaw, _ := record.Get("tags")
99 serialRaw, _ := record.Get("serial")
100
101 idStr, _ := idRaw.(string)
102 kind, _ := kindRaw.(int64)
103 createdAt, _ := createdAtRaw.(int64)
104 content, _ := contentRaw.(string)
105 sigStr, _ := sigRaw.(string)
106 pubkeyStr, _ := pubkeyRaw.(string)
107 tagsStr, _ := tagsRaw.(string)
108 serialVal, _ := serialRaw.(int64)
109
110 id, err := hex.Dec(idStr)
111 if err != nil {
112 continue
113 }
114 sig, err := hex.Dec(sigStr)
115 if err != nil {
116 continue
117 }
118 pubkey, err := hex.Dec(pubkeyStr)
119 if err != nil {
120 continue
121 }
122
123 tags := tag.NewS()
124 if tagsStr != "" {
125 _ = tags.UnmarshalJSON([]byte(tagsStr))
126 }
127
128 e := &event.E{
129 Kind: uint16(kind),
130 CreatedAt: createdAt,
131 Content: []byte(content),
132 Tags: tags,
133 }
134
135 copy(e.ID[:], id)
136 copy(e.Sig[:], sig)
137 copy(e.Pubkey[:], pubkey)
138
139 events[uint64(serialVal)] = e
140 }
141
142 return events, nil
143 }
144
145 // GetSerialById retrieves the serial number for an event ID
146 func (n *N) GetSerialById(id []byte) (ser *types.Uint40, err error) {
147 idStr := hex.Enc(id)
148
149 cypher := "MATCH (e:Event {id: $id}) RETURN e.serial AS serial"
150 params := map[string]any{"id": idStr}
151
152 result, err := n.ExecuteRead(context.Background(), cypher, params)
153 if err != nil {
154 return nil, fmt.Errorf("failed to get serial by ID: %w", err)
155 }
156
157 ctx := context.Background()
158
159 if result.Next(ctx) {
160 record := result.Record()
161 if record != nil {
162 serialRaw, found := record.Get("serial")
163 if found {
164 if serialVal, ok := serialRaw.(int64); ok {
165 ser = &types.Uint40{}
166 ser.Set(uint64(serialVal))
167 return ser, nil
168 }
169 }
170 }
171 }
172
173 return nil, fmt.Errorf("event not found")
174 }
175
176 // GetSerialsByIds retrieves serial numbers for multiple event IDs
177 func (n *N) GetSerialsByIds(ids *tag.T) (
178 serials map[string]*types.Uint40, err error,
179 ) {
180 serials = make(map[string]*types.Uint40)
181
182 if len(ids.T) == 0 {
183 return serials, nil
184 }
185
186 // Extract ID strings
187 idStrs := make([]string, 0, len(ids.T))
188 for _, idTag := range ids.T {
189 if len(idTag) >= 2 {
190 idStrs = append(idStrs, string(idTag[1]))
191 }
192 }
193
194 if len(idStrs) == 0 {
195 return serials, nil
196 }
197
198 cypher := `
199 MATCH (e:Event)
200 WHERE e.id IN $ids
201 RETURN e.id AS id, e.serial AS serial`
202
203 params := map[string]any{"ids": idStrs}
204
205 result, err := n.ExecuteRead(context.Background(), cypher, params)
206 if err != nil {
207 return nil, fmt.Errorf("failed to get serials by IDs: %w", err)
208 }
209
210 ctx := context.Background()
211
212 for result.Next(ctx) {
213 record := result.Record()
214 if record == nil {
215 continue
216 }
217
218 idRaw, found := record.Get("id")
219 if !found {
220 continue
221 }
222 serialRaw, found := record.Get("serial")
223 if !found {
224 continue
225 }
226
227 idStr, _ := idRaw.(string)
228 serialVal, _ := serialRaw.(int64)
229
230 serial := &types.Uint40{}
231 serial.Set(uint64(serialVal))
232 serials[idStr] = serial
233 }
234
235 return serials, nil
236 }
237
238 // GetSerialsByIdsWithFilter retrieves serials with a filter function
239 func (n *N) GetSerialsByIdsWithFilter(
240 ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool,
241 ) (serials map[string]*types.Uint40, err error) {
242 serials = make(map[string]*types.Uint40)
243
244 if fn == nil {
245 // No filter, just return all
246 return n.GetSerialsByIds(ids)
247 }
248
249 // With filter, need to fetch events
250 for _, idTag := range ids.T {
251 if len(idTag) < 2 {
252 continue
253 }
254
255 idBytes, err := hex.Dec(string(idTag[1]))
256 if err != nil {
257 continue
258 }
259
260 serial, err := n.GetSerialById(idBytes)
261 if err != nil {
262 continue
263 }
264
265 ev, err := n.FetchEventBySerial(serial)
266 if err != nil {
267 continue
268 }
269
270 if fn(ev, serial) {
271 serials[string(idTag[1])] = serial
272 }
273 }
274
275 return serials, nil
276 }
277
278 // GetSerialsByRange retrieves serials within a range
279 func (n *N) GetSerialsByRange(idx database.Range) (
280 serials types.Uint40s, err error,
281 ) {
282 // This would need to be implemented based on how ranges are defined
283 // For now, returning not implemented
284 err = fmt.Errorf("not implemented")
285 return
286 }
287
288 // GetFullIdPubkeyBySerial retrieves ID and pubkey for a serial number
289 func (n *N) GetFullIdPubkeyBySerial(ser *types.Uint40) (
290 fidpk *store.IdPkTs, err error,
291 ) {
292 serial := ser.Get()
293
294 cypher := `
295 MATCH (e:Event {serial: $serial})
296 RETURN e.id AS id,
297 e.pubkey AS pubkey,
298 e.created_at AS created_at`
299
300 params := map[string]any{"serial": int64(serial)}
301
302 result, err := n.ExecuteRead(context.Background(), cypher, params)
303 if err != nil {
304 return nil, fmt.Errorf("failed to get ID and pubkey by serial: %w", err)
305 }
306
307 ctx := context.Background()
308
309 if result.Next(ctx) {
310 record := result.Record()
311 if record != nil {
312 idRaw, found := record.Get("id")
313 if !found {
314 return nil, fmt.Errorf("event not found")
315 }
316 pubkeyRaw, found := record.Get("pubkey")
317 if !found {
318 return nil, fmt.Errorf("event not found")
319 }
320 createdAtRaw, found := record.Get("created_at")
321 if !found {
322 return nil, fmt.Errorf("event not found")
323 }
324
325 idStr, _ := idRaw.(string)
326 pubkeyStr, _ := pubkeyRaw.(string)
327 createdAt, _ := createdAtRaw.(int64)
328
329 id, err := hex.Dec(idStr)
330 if err != nil {
331 return nil, err
332 }
333
334 pubkey, err := hex.Dec(pubkeyStr)
335 if err != nil {
336 return nil, err
337 }
338
339 idpkts := store.NewIdPkTs(id, pubkey, createdAt, serial)
340 fidpk = &idpkts
341
342 return fidpk, nil
343 }
344 }
345
346 return nil, fmt.Errorf("event not found")
347 }
348
349 // GetFullIdPubkeyBySerials retrieves IDs and pubkeys for multiple serials
350 func (n *N) GetFullIdPubkeyBySerials(sers []*types.Uint40) (
351 fidpks []*store.IdPkTs, err error,
352 ) {
353 fidpks = make([]*store.IdPkTs, 0, len(sers))
354
355 if len(sers) == 0 {
356 return fidpks, nil
357 }
358
359 // Build list of serial numbers
360 serialNums := make([]int64, len(sers))
361 for i, ser := range sers {
362 serialNums[i] = int64(ser.Get())
363 }
364
365 cypher := `
366 MATCH (e:Event)
367 WHERE e.serial IN $serials
368 RETURN e.id AS id,
369 e.pubkey AS pubkey,
370 e.created_at AS created_at,
371 e.serial AS serial`
372
373 params := map[string]any{"serials": serialNums}
374
375 result, err := n.ExecuteRead(context.Background(), cypher, params)
376 if err != nil {
377 return nil, fmt.Errorf("failed to get IDs and pubkeys by serials: %w", err)
378 }
379
380 ctx := context.Background()
381
382 for result.Next(ctx) {
383 record := result.Record()
384 if record == nil {
385 continue
386 }
387
388 idRaw, found := record.Get("id")
389 if !found {
390 continue
391 }
392 pubkeyRaw, found := record.Get("pubkey")
393 if !found {
394 continue
395 }
396 createdAtRaw, found := record.Get("created_at")
397 if !found {
398 continue
399 }
400 serialRaw, found := record.Get("serial")
401 if !found {
402 continue
403 }
404
405 idStr, _ := idRaw.(string)
406 pubkeyStr, _ := pubkeyRaw.(string)
407 createdAt, _ := createdAtRaw.(int64)
408 serialVal, _ := serialRaw.(int64)
409
410 id, err := hex.Dec(idStr)
411 if err != nil {
412 continue
413 }
414
415 pubkey, err := hex.Dec(pubkeyStr)
416 if err != nil {
417 continue
418 }
419
420 idpkts := store.NewIdPkTs(id, pubkey, createdAt, uint64(serialVal))
421 fidpks = append(fidpks, &idpkts)
422 }
423
424 return fidpks, nil
425 }
426