You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
3.8 KiB
143 lines
3.8 KiB
package neo4j |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"strings" |
|
|
|
"git.mleku.dev/mleku/nostr/encoders/hex" |
|
"next.orly.dev/pkg/protocol/graph" |
|
) |
|
|
|
// FindMentions finds events that mention a pubkey via p-tags. |
|
// This returns events grouped by depth, where depth represents how the events relate: |
|
// - Depth 1: Events that directly mention the seed pubkey |
|
// - Depth 2+: Not typically used for mentions (reserved for future expansion) |
|
// |
|
// The kinds parameter filters which event kinds to include (e.g., [1] for notes only, |
|
// [1,7] for notes and reactions, etc.) |
|
// |
|
// Uses Neo4j MENTIONS relationships created by SaveEvent when processing p-tags. |
|
func (n *N) FindMentions(pubkey []byte, kinds []uint16) (graph.GraphResultI, error) { |
|
result := NewGraphResult() |
|
|
|
if len(pubkey) != 32 { |
|
return result, fmt.Errorf("invalid pubkey length: expected 32, got %d", len(pubkey)) |
|
} |
|
|
|
pubkeyHex := strings.ToLower(hex.Enc(pubkey)) |
|
ctx := context.Background() |
|
|
|
// Build kinds filter if specified |
|
var kindsFilter string |
|
params := map[string]any{ |
|
"pubkey": pubkeyHex, |
|
} |
|
|
|
if len(kinds) > 0 { |
|
// Convert uint16 slice to int64 slice for Neo4j |
|
kindsInt := make([]int64, len(kinds)) |
|
for i, k := range kinds { |
|
kindsInt[i] = int64(k) |
|
} |
|
params["kinds"] = kindsInt |
|
kindsFilter = "AND e.kind IN $kinds" |
|
} |
|
|
|
// Query for events that mention this pubkey |
|
// The MENTIONS relationship is created by SaveEvent when processing p-tags |
|
cypher := fmt.Sprintf(` |
|
MATCH (e:Event)-[:MENTIONS]->(u:NostrUser {pubkey: $pubkey}) |
|
WHERE true %s |
|
RETURN e.id AS event_id |
|
ORDER BY e.created_at DESC |
|
`, kindsFilter) |
|
|
|
queryResult, err := n.ExecuteRead(ctx, cypher, params) |
|
if err != nil { |
|
return result, fmt.Errorf("failed to query mentions: %w", err) |
|
} |
|
|
|
// Add all found events at depth 1 |
|
for queryResult.Next(ctx) { |
|
record := queryResult.Record() |
|
eventID, ok := record.Values[0].(string) |
|
if !ok || eventID == "" { |
|
continue |
|
} |
|
|
|
// Normalize to lowercase for consistency |
|
eventID = strings.ToLower(eventID) |
|
result.AddEventAtDepth(eventID, 1) |
|
} |
|
|
|
n.Logger.Debugf("FindMentions: found %d events mentioning pubkey %s", result.TotalEvents, safePrefix(pubkeyHex, 16)) |
|
|
|
return result, nil |
|
} |
|
|
|
// FindMentionsFromHex is a convenience wrapper that accepts hex-encoded pubkey. |
|
func (n *N) FindMentionsFromHex(pubkeyHex string, kinds []uint16) (*GraphResult, error) { |
|
pubkey, err := hex.Dec(pubkeyHex) |
|
if err != nil { |
|
return nil, err |
|
} |
|
result, err := n.FindMentions(pubkey, kinds) |
|
if err != nil { |
|
return nil, err |
|
} |
|
return result.(*GraphResult), nil |
|
} |
|
|
|
// FindMentionsByPubkeys returns events that mention any of the given pubkeys. |
|
// Useful for finding mentions across a set of followed accounts. |
|
func (n *N) FindMentionsByPubkeys(pubkeys []string, kinds []uint16) (*GraphResult, error) { |
|
result := NewGraphResult() |
|
|
|
if len(pubkeys) == 0 { |
|
return result, nil |
|
} |
|
|
|
ctx := context.Background() |
|
|
|
// Build kinds filter if specified |
|
var kindsFilter string |
|
params := map[string]any{ |
|
"pubkeys": pubkeys, |
|
} |
|
|
|
if len(kinds) > 0 { |
|
kindsInt := make([]int64, len(kinds)) |
|
for i, k := range kinds { |
|
kindsInt[i] = int64(k) |
|
} |
|
params["kinds"] = kindsInt |
|
kindsFilter = "AND e.kind IN $kinds" |
|
} |
|
|
|
// Query for events that mention any of the pubkeys |
|
cypher := fmt.Sprintf(` |
|
MATCH (e:Event)-[:MENTIONS]->(u:NostrUser) |
|
WHERE u.pubkey IN $pubkeys %s |
|
RETURN DISTINCT e.id AS event_id |
|
ORDER BY e.created_at DESC |
|
`, kindsFilter) |
|
|
|
queryResult, err := n.ExecuteRead(ctx, cypher, params) |
|
if err != nil { |
|
return result, fmt.Errorf("failed to query mentions: %w", err) |
|
} |
|
|
|
for queryResult.Next(ctx) { |
|
record := queryResult.Record() |
|
eventID, ok := record.Values[0].(string) |
|
if !ok || eventID == "" { |
|
continue |
|
} |
|
|
|
eventID = strings.ToLower(eventID) |
|
result.AddEventAtDepth(eventID, 1) |
|
} |
|
|
|
return result, nil |
|
}
|
|
|