graph-adapter.go raw

   1  package neo4j
   2  
   3  import (
   4  	"fmt"
   5  
   6  	"next.orly.dev/pkg/protocol/graph"
   7  )
   8  
   9  // GraphAdapter wraps a Neo4j database instance and implements graph.GraphDatabase interface.
  10  type GraphAdapter struct {
  11  	db *N
  12  }
  13  
  14  // NewGraphAdapter creates a new GraphAdapter wrapping the given Neo4j database.
  15  func NewGraphAdapter(db *N) *GraphAdapter {
  16  	return &GraphAdapter{db: db}
  17  }
  18  
  19  // TraversePubkeyPubkey implements graph.GraphDatabase.
  20  // Neo4j uses Cypher queries for direct pubkey-to-pubkey traversal.
  21  func (a *GraphAdapter) TraversePubkeyPubkey(seedPubkey []byte, maxDepth int, direction string) (graph.GraphResultI, error) {
  22  	switch direction {
  23  	case "out":
  24  		return a.db.TraverseFollows(seedPubkey, maxDepth)
  25  	case "in":
  26  		return a.db.TraverseFollowers(seedPubkey, maxDepth)
  27  	case "both":
  28  		// For bidirectional, execute both and merge
  29  		outResult, err := a.db.TraverseFollows(seedPubkey, maxDepth)
  30  		if err != nil {
  31  			return nil, err
  32  		}
  33  		inResult, err := a.db.TraverseFollowers(seedPubkey, maxDepth)
  34  		if err != nil {
  35  			return outResult, nil // Return what we have
  36  		}
  37  		// Merge inbound results into outbound
  38  		mergeResults(outResult, inResult)
  39  		return outResult, nil
  40  	default:
  41  		return nil, fmt.Errorf("invalid direction: %s", direction)
  42  	}
  43  }
  44  
  45  // TraversePubkeyEvent implements graph.GraphDatabase.
  46  func (a *GraphAdapter) TraversePubkeyEvent(seedPubkey []byte, maxDepth int, direction string) (graph.GraphResultI, error) {
  47  	// Delegate to mentions for now (pe queries)
  48  	return a.db.FindMentions(seedPubkey, nil)
  49  }
  50  
  51  // TraverseEventEvent implements graph.GraphDatabase.
  52  func (a *GraphAdapter) TraverseEventEvent(seedEventID []byte, maxDepth int, direction string) (graph.GraphResultI, error) {
  53  	return a.db.TraverseThread(seedEventID, maxDepth, direction)
  54  }
  55  
  56  // TraversePubkeyPubkeyBaseline implements graph.GraphDatabase.
  57  // For Neo4j, baseline is the same as optimized since Neo4j handles its own query planning.
  58  func (a *GraphAdapter) TraversePubkeyPubkeyBaseline(seedPubkey []byte, maxDepth int, direction string) (graph.GraphResultI, error) {
  59  	return a.TraversePubkeyPubkey(seedPubkey, maxDepth, direction)
  60  }
  61  
  62  // mergeResults merges source GraphResultI into target.
  63  // This is a best-effort merge using the interface methods.
  64  func mergeResults(target, source graph.GraphResultI) {
  65  	// Results are read-only through the interface — for Neo4j this is acceptable
  66  	// since Cypher can do bidirectional in a single query if needed.
  67  	_ = target
  68  	_ = source
  69  }
  70  
  71  // Verify GraphAdapter implements graph.GraphDatabase
  72  var _ graph.GraphDatabase = (*GraphAdapter)(nil)
  73