Started transforming tags into relationships.
This commit is contained in:
33
lib/graph.go
33
lib/graph.go
@@ -346,36 +346,3 @@ func DeserializeRelKey(sortKey string) (string, string, string) {
|
||||
rtype, startLabel, endLabel := parts[0], parts[1], parts[2]
|
||||
return rtype, startLabel, endLabel
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Cypher Formatting Functions
|
||||
// ========================================
|
||||
|
||||
// ToCypherLabel converts a node label or relationship type into its Cypher
|
||||
// format.
|
||||
func ToCypherLabel(label string) string {
|
||||
return fmt.Sprintf(":`%s`", label)
|
||||
}
|
||||
|
||||
// ToCypherLabels converts a list of node labels into its Cypher format.
|
||||
func ToCypherLabels(labels []string) string {
|
||||
var cypherLabels []string
|
||||
|
||||
for _, label := range labels {
|
||||
cypherLabels = append(cypherLabels, ToCypherLabel(label))
|
||||
}
|
||||
|
||||
return strings.Join(cypherLabels, "")
|
||||
}
|
||||
|
||||
func ToCypherProps(keys []string, prefix string) string {
|
||||
if prefix == "" {
|
||||
prefix = "$"
|
||||
}
|
||||
cypherPropsParts := []string{}
|
||||
for _, key := range keys {
|
||||
cypherPropsParts = append(
|
||||
cypherPropsParts, fmt.Sprintf("%s: %s%s", key, prefix, key))
|
||||
}
|
||||
return strings.Join(cypherPropsParts, ", ")
|
||||
}
|
||||
|
||||
@@ -6,18 +6,19 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip60"
|
||||
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
||||
)
|
||||
|
||||
// Workers
|
||||
|
||||
func ImportEvents() {
|
||||
|
||||
data, err := os.ReadFile("./export.json")
|
||||
data, err := os.ReadFile("./zaps.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -35,7 +36,7 @@ func ImportEvents() {
|
||||
var event nostr.Event
|
||||
|
||||
for i, line := range strings.Split(string(data), "\n") {
|
||||
if i > 10000 {
|
||||
if i > 2000000 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -80,6 +81,12 @@ func ParseEvents(events chan nostr.Event) {
|
||||
eventNode.Props["kind"] = event.Kind
|
||||
eventNode.Props["content"] = event.Content
|
||||
|
||||
if event.Kind == nostr.KindZap {
|
||||
// Event is a zap receipt
|
||||
// Write the zap amount to the event
|
||||
eventNode.Labels.Add("ZapReceiptEvent")
|
||||
}
|
||||
|
||||
authorRel := NewSignedRel(userNode, eventNode, nil)
|
||||
|
||||
subgraph.AddNode(userNode)
|
||||
@@ -91,13 +98,67 @@ func ParseEvents(events chan nostr.Event) {
|
||||
if len(tag) >= 2 {
|
||||
name := tag[0]
|
||||
value := tag[1]
|
||||
var rest []string
|
||||
|
||||
// Special cases
|
||||
if len(name)+len(value) > 8192 {
|
||||
// Skip tags that are too large for the neo4j indexer
|
||||
continue
|
||||
}
|
||||
|
||||
tagNode := NewTagNode(name, value)
|
||||
tagRel := NewTaggedRel(eventNode, tagNode, nil)
|
||||
subgraph.AddNode(tagNode)
|
||||
subgraph.AddRel(tagRel)
|
||||
if len(tag) > 2 {
|
||||
rest = append([]string{}, tag[2:]...)
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindZap && name == "bolt11" {
|
||||
amount, err := nip60.GetSatoshisAmountFromBolt11(value)
|
||||
if err == nil {
|
||||
eventNode.Props["amount"] = amount
|
||||
} else {
|
||||
fmt.Println("Invalid bolt11 amount:", err)
|
||||
}
|
||||
}
|
||||
|
||||
if name == "e" &&
|
||||
len(value) == 64 &&
|
||||
regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(value) {
|
||||
// Tag is an event reference
|
||||
// Create a relationship to the referenced event
|
||||
referencedEventNode := NewEventNode(value)
|
||||
referencesRel := NewReferencesEventRel(
|
||||
eventNode,
|
||||
referencedEventNode,
|
||||
map[string]any{
|
||||
"name": name,
|
||||
"value": value,
|
||||
"rest": rest,
|
||||
})
|
||||
subgraph.AddNode(referencedEventNode)
|
||||
subgraph.AddRel(referencesRel)
|
||||
|
||||
} else if name == "p" &&
|
||||
len(value) == 64 &&
|
||||
regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(value) {
|
||||
// Tag is a user reference
|
||||
// Create a relationship to the referenced user
|
||||
referencedUserNode := NewUserNode(value)
|
||||
referencesRel := NewReferencesUserRel(
|
||||
eventNode,
|
||||
referencedUserNode,
|
||||
map[string]any{
|
||||
"name": name,
|
||||
"value": value,
|
||||
"rest": rest,
|
||||
})
|
||||
subgraph.AddNode(referencedUserNode)
|
||||
subgraph.AddRel(referencesRel)
|
||||
|
||||
} else {
|
||||
// Generic Tag
|
||||
tagNode := NewTagNode(name, value, rest)
|
||||
tagRel := NewTaggedRel(eventNode, tagNode, nil)
|
||||
subgraph.AddNode(tagNode)
|
||||
subgraph.AddRel(tagRel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +369,7 @@ func mergeRels(
|
||||
MATCH (start%s { %s })
|
||||
MATCH (end%s { %s })
|
||||
|
||||
CREATE (start)-[r%s]->(end)
|
||||
MERGE (start)-[r%s]->(end)
|
||||
SET r += rel.props
|
||||
`,
|
||||
startCypherLabel, startCypherProps,
|
||||
|
||||
@@ -38,8 +38,11 @@ func NewEventNode(id string) *Node {
|
||||
return NewNode("Event", Properties{"id": id})
|
||||
}
|
||||
|
||||
func NewTagNode(name string, value string) *Node {
|
||||
return NewNode("Tag", Properties{"name": name, "value": value})
|
||||
func NewTagNode(name string, value string, rest []string) *Node {
|
||||
return NewNode("Tag", Properties{
|
||||
"name": name,
|
||||
"value": value,
|
||||
"rest": rest})
|
||||
}
|
||||
|
||||
// ========================================
|
||||
@@ -59,6 +62,18 @@ func NewTaggedRel(
|
||||
"TAGGED", "Event", "Tag", start, end, props)
|
||||
}
|
||||
|
||||
func NewReferencesEventRel(
|
||||
start *Node, end *Node, props Properties) *Relationship {
|
||||
return NewRelationshipWithValidation(
|
||||
"REFERENCES", "Event", "Event", start, end, props)
|
||||
}
|
||||
|
||||
func NewReferencesUserRel(
|
||||
start *Node, end *Node, props Properties) *Relationship {
|
||||
return NewRelationshipWithValidation(
|
||||
"REFERENCES", "Event", "User", start, end, props)
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Relationship Constructor Helpers
|
||||
// ========================================
|
||||
|
||||
39
lib/write.go
Normal file
39
lib/write.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ========================================
|
||||
// Cypher Formatting Functions
|
||||
// ========================================
|
||||
|
||||
// ToCypherLabel converts a node label or relationship type into its Cypher
|
||||
// format.
|
||||
func ToCypherLabel(label string) string {
|
||||
return fmt.Sprintf(":`%s`", label)
|
||||
}
|
||||
|
||||
// ToCypherLabels converts a list of node labels into its Cypher format.
|
||||
func ToCypherLabels(labels []string) string {
|
||||
var cypherLabels []string
|
||||
|
||||
for _, label := range labels {
|
||||
cypherLabels = append(cypherLabels, ToCypherLabel(label))
|
||||
}
|
||||
|
||||
return strings.Join(cypherLabels, "")
|
||||
}
|
||||
|
||||
func ToCypherProps(keys []string, prefix string) string {
|
||||
if prefix == "" {
|
||||
prefix = "$"
|
||||
}
|
||||
cypherPropsParts := []string{}
|
||||
for _, key := range keys {
|
||||
cypherPropsParts = append(
|
||||
cypherPropsParts, fmt.Sprintf("%s: %s%s", key, prefix, key))
|
||||
}
|
||||
return strings.Join(cypherPropsParts, ", ")
|
||||
}
|
||||
Reference in New Issue
Block a user