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