Refactored repository structure.

This commit is contained in:
Jay
2026-03-03 13:34:10 -05:00
parent 96f1ceb362
commit e9e153c9a1
15 changed files with 159 additions and 144 deletions

View File

@@ -1,4 +1,4 @@
package heartwood package cypher
import ( import (
"fmt" "fmt"

View File

@@ -1,4 +1,4 @@
package heartwood package cypher
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@@ -1,10 +1,11 @@
package heartwood package heartwood
import ( import (
"git.wisehodl.dev/jay/go-heartwood/graph"
roots "git.wisehodl.dev/jay/go-roots/events" roots "git.wisehodl.dev/jay/go-roots/events"
) )
type Expander func(e roots.Event, s *Subgraph) type Expander func(e roots.Event, s *graph.Subgraph)
type ExpanderRegistry []Expander type ExpanderRegistry []Expander
func NewExpanderRegistry() ExpanderRegistry { func NewExpanderRegistry() ExpanderRegistry {
@@ -26,7 +27,7 @@ func (r *ExpanderRegistry) Add(m Expander) {
// Default Expander Functions // Default Expander Functions
func ExpandTaggedEvents(e roots.Event, s *Subgraph) { func ExpandTaggedEvents(e roots.Event, s *graph.Subgraph) {
tagNodes := s.NodesByLabel("Tag") tagNodes := s.NodesByLabel("Tag")
for _, tag := range e.Tags { for _, tag := range e.Tags {
if !isValidTag(tag) { if !isValidTag(tag) {
@@ -44,14 +45,14 @@ func ExpandTaggedEvents(e roots.Event, s *Subgraph) {
continue continue
} }
referencedEvent := NewEventNode(value) referencedEvent := graph.NewEventNode(value)
s.AddNode(referencedEvent) s.AddNode(referencedEvent)
s.AddRel(NewReferencesEventRel(tagNode, referencedEvent, nil)) s.AddRel(graph.NewReferencesEventRel(tagNode, referencedEvent, nil))
} }
} }
func ExpandTaggedUsers(e roots.Event, s *Subgraph) { func ExpandTaggedUsers(e roots.Event, s *graph.Subgraph) {
tagNodes := s.NodesByLabel("Tag") tagNodes := s.NodesByLabel("Tag")
for _, tag := range e.Tags { for _, tag := range e.Tags {
if !isValidTag(tag) { if !isValidTag(tag) {
@@ -69,16 +70,16 @@ func ExpandTaggedUsers(e roots.Event, s *Subgraph) {
continue continue
} }
referencedEvent := NewUserNode(value) referencedEvent := graph.NewUserNode(value)
s.AddNode(referencedEvent) s.AddNode(referencedEvent)
s.AddRel(NewReferencesUserRel(tagNode, referencedEvent, nil)) s.AddRel(graph.NewReferencesUserRel(tagNode, referencedEvent, nil))
} }
} }
// Helpers // Helpers
func findTagNode(nodes []*Node, name, value string) *Node { func findTagNode(nodes []*graph.Node, name, value string) *graph.Node {
for _, node := range nodes { for _, node := range nodes {
if node.Props["name"] == name && node.Props["value"] == value { if node.Props["name"] == name && node.Props["value"] == value {
return node return node

5
go.mod
View File

@@ -3,12 +3,17 @@ module git.wisehodl.dev/jay/go-heartwood
go 1.24 go 1.24
require ( require (
git.wisehodl.dev/jay/go-roots v0.3.1
github.com/neo4j/neo4j-go-driver/v6 v6.0.0 github.com/neo4j/neo4j-go-driver/v6 v6.0.0
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
) )
require ( require (
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

10
go.sum
View File

@@ -1,5 +1,15 @@
git.wisehodl.dev/jay/go-roots v0.3.1 h1:5UiG3g1S3XCkMB+W2rbNZGpl4IiSlRvae2cLHGfjVcA=
git.wisehodl.dev/jay/go-roots v0.3.1/go.mod h1:TQXk/V8MRSw4khMlNSINM8dU5/ARR1Wov+kGw0237rQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU=
github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/neo4j/neo4j-go-driver/v6 v6.0.0 h1:xVAi6YLOfzXUx+1Lc/F2dUhpbN76BfKleZbAlnDFRiA= github.com/neo4j/neo4j-go-driver/v6 v6.0.0 h1:xVAi6YLOfzXUx+1Lc/F2dUhpbN76BfKleZbAlnDFRiA=
github.com/neo4j/neo4j-go-driver/v6 v6.0.0/go.mod h1:hzSTfNfM31p1uRSzL1F/BAYOgaiTarE6OAQBajfsm+I= github.com/neo4j/neo4j-go-driver/v6 v6.0.0/go.mod h1:hzSTfNfM31p1uRSzL1F/BAYOgaiTarE6OAQBajfsm+I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -1,7 +1,7 @@
// This module defines types and functions for working with Neo4j graph // This module defines types and functions for working with Neo4j graph
// entities. // entities.
package heartwood package graph
import ( import (
"fmt" "fmt"
@@ -33,19 +33,19 @@ type MatchKeysProvider interface {
// MatchKeys is a simple implementation of the MatchKeysProvider interface. // MatchKeys is a simple implementation of the MatchKeysProvider interface.
type MatchKeys struct { type MatchKeys struct {
keys map[string][]string Keys map[string][]string
} }
func (p *MatchKeys) GetLabels() []string { func (p *MatchKeys) GetLabels() []string {
labels := []string{} labels := []string{}
for l := range p.keys { for l := range p.Keys {
labels = append(labels, l) labels = append(labels, l)
} }
return labels return labels
} }
func (p *MatchKeys) GetKeys(label string) ([]string, bool) { func (p *MatchKeys) GetKeys(label string) ([]string, bool) {
if keys, exists := p.keys[label]; exists { if keys, exists := p.Keys[label]; exists {
return keys, exists return keys, exists
} else { } else {
return nil, exists return nil, exists
@@ -296,6 +296,10 @@ func (s *StructuredSubgraph) GetRels(relKey string) []*Relationship {
return s.rels[relKey] return s.rels[relKey]
} }
func (s *StructuredSubgraph) MatchProvider() MatchKeysProvider {
return s.matchProvider
}
// NodeCount returns the number of nodes in the subgraph. // NodeCount returns the number of nodes in the subgraph.
func (s *StructuredSubgraph) NodeCount() int { func (s *StructuredSubgraph) NodeCount() int {
count := 0 count := 0

View File

@@ -1,4 +1,4 @@
package heartwood package graph
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -7,7 +7,7 @@ import (
func TestMatchKeys(t *testing.T) { func TestMatchKeys(t *testing.T) {
matchKeys := &MatchKeys{ matchKeys := &MatchKeys{
keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Event": {"id"}, "Event": {"id"},
"Tag": {"name", "value"}, "Tag": {"name", "value"},
@@ -70,7 +70,7 @@ func TestRelSortKey(t *testing.T) {
func TestMatchProps(t *testing.T) { func TestMatchProps(t *testing.T) {
matchKeys := &MatchKeys{ matchKeys := &MatchKeys{
keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Event": {"id"}, "Event": {"id"},
}, },

View File

@@ -1,12 +1,10 @@
// This module provides methods for creating nodes and relationships according // This module provides methods for creating nodes and relationships according
// to a defined schema. // to a defined schema.
package heartwood package graph
import ( import (
"context"
"fmt" "fmt"
"github.com/neo4j/neo4j-go-driver/v6/neo4j"
) )
// ======================================== // ========================================
@@ -15,7 +13,7 @@ import (
func NewMatchKeys() *MatchKeys { func NewMatchKeys() *MatchKeys {
return &MatchKeys{ return &MatchKeys{
keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Relay": {"url"}, "Relay": {"url"},
"Event": {"id"}, "Event": {"id"},
@@ -101,43 +99,3 @@ func NewRelationshipWithValidation(
return NewRelationship(rtype, start, end, props) return NewRelationship(rtype, start, end, props)
} }
// ========================================
// Schema Indexes and Constaints
// ========================================
// SetNeo4jSchema ensures that the necessary indexes and constraints exist in
// the database
func SetNeo4jSchema(ctx context.Context, driver neo4j.Driver) error {
schemaQueries := []string{
`CREATE CONSTRAINT user_pubkey IF NOT EXISTS
FOR (n:User) REQUIRE n.pubkey IS UNIQUE`,
`CREATE INDEX user_pubkey IF NOT EXISTS
FOR (n:User) ON (n.pubkey)`,
`CREATE INDEX event_id IF NOT EXISTS
FOR (n:Event) ON (n.id)`,
`CREATE INDEX event_kind IF NOT EXISTS
FOR (n:Event) ON (n.kind)`,
`CREATE INDEX tag_name_value IF NOT EXISTS
FOR (n:Tag) ON (n.name, n.value)`,
}
// Create indexes and constraints
for _, query := range schemaQueries {
_, err := neo4j.ExecuteQuery(ctx, driver,
query,
nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
package heartwood package graph
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@@ -1,4 +1,4 @@
package heartwood package graph
// Sets // Sets
@@ -52,15 +52,3 @@ func (s Set[T]) ToArray() []T {
} }
return array return array
} }
// Operations
func Flatten[K comparable, V comparable](mapping map[K][]V) []V {
var values []V
for _, array := range mapping {
for _, v := range array {
values = append(values, v)
}
}
return values
}

View File

@@ -1,41 +1,43 @@
package heartwood package graphstore
import ( import (
"context" "context"
"fmt" "fmt"
"git.wisehodl.dev/jay/go-heartwood/cypher"
"git.wisehodl.dev/jay/go-heartwood/graph"
"github.com/neo4j/neo4j-go-driver/v6/neo4j" "github.com/neo4j/neo4j-go-driver/v6/neo4j"
) )
func MergeSubgraph( func MergeSubgraph(
ctx context.Context, ctx context.Context,
driver neo4j.Driver, driver neo4j.Driver,
subgraph *StructuredSubgraph, subgraph *graph.StructuredSubgraph,
) ([]neo4j.ResultSummary, error) { ) ([]neo4j.ResultSummary, error) {
// Validate subgraph // Validate subgraph
for _, nodeKey := range subgraph.NodeKeys() { for _, nodeKey := range subgraph.NodeKeys() {
matchLabel, _, err := DeserializeNodeKey(nodeKey) matchLabel, _, err := graph.DeserializeNodeKey(nodeKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, exists := subgraph.matchProvider.GetKeys(matchLabel) _, exists := subgraph.MatchProvider().GetKeys(matchLabel)
if !exists { if !exists {
return nil, fmt.Errorf("unknown match label: %s", matchLabel) return nil, fmt.Errorf("unknown match label: %s", matchLabel)
} }
} }
for _, relKey := range subgraph.RelKeys() { for _, relKey := range subgraph.RelKeys() {
_, startLabel, endLabel, err := DeserializeRelKey(relKey) _, startLabel, endLabel, err := graph.DeserializeRelKey(relKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, exists := subgraph.matchProvider.GetKeys(startLabel) _, exists := subgraph.MatchProvider().GetKeys(startLabel)
if !exists { if !exists {
return nil, fmt.Errorf("unknown match label: %s", startLabel) return nil, fmt.Errorf("unknown match label: %s", startLabel)
} }
_, exists = subgraph.matchProvider.GetKeys(endLabel) _, exists = subgraph.MatchProvider().GetKeys(endLabel)
if !exists { if !exists {
return nil, fmt.Errorf("unknown match label: %s", endLabel) return nil, fmt.Errorf("unknown match label: %s", endLabel)
} }
@@ -49,12 +51,12 @@ func MergeSubgraph(
var resultSummaries []neo4j.ResultSummary var resultSummaries []neo4j.ResultSummary
for _, nodeKey := range subgraph.NodeKeys() { for _, nodeKey := range subgraph.NodeKeys() {
matchLabel, labels, _ := DeserializeNodeKey(nodeKey) matchLabel, labels, _ := graph.DeserializeNodeKey(nodeKey)
nodeResultSummary, err := MergeNodes( nodeResultSummary, err := MergeNodes(
ctx, tx, ctx, tx,
matchLabel, matchLabel,
labels, labels,
subgraph.matchProvider, subgraph.MatchProvider(),
subgraph.GetNodes(nodeKey), subgraph.GetNodes(nodeKey),
) )
if err != nil { if err != nil {
@@ -66,13 +68,13 @@ func MergeSubgraph(
} }
for _, relKey := range subgraph.RelKeys() { for _, relKey := range subgraph.RelKeys() {
rtype, startLabel, endLabel, _ := DeserializeRelKey(relKey) rtype, startLabel, endLabel, _ := graph.DeserializeRelKey(relKey)
relResultSummary, err := MergeRels( relResultSummary, err := MergeRels(
ctx, tx, ctx, tx,
rtype, rtype,
startLabel, startLabel,
endLabel, endLabel,
subgraph.matchProvider, subgraph.MatchProvider(),
subgraph.GetRels(relKey), subgraph.GetRels(relKey),
) )
if err != nil { if err != nil {
@@ -103,15 +105,15 @@ func MergeNodes(
tx neo4j.ManagedTransaction, tx neo4j.ManagedTransaction,
matchLabel string, matchLabel string,
nodeLabels []string, nodeLabels []string,
matchProvider MatchKeysProvider, matchProvider graph.MatchKeysProvider,
nodes []*Node, nodes []*graph.Node,
) (*neo4j.ResultSummary, error) { ) (*neo4j.ResultSummary, error) {
cypherLabels := ToCypherLabels(nodeLabels) cypherLabels := cypher.ToCypherLabels(nodeLabels)
matchKeys, _ := matchProvider.GetKeys(matchLabel) matchKeys, _ := matchProvider.GetKeys(matchLabel)
cypherProps := ToCypherProps(matchKeys, "node.") cypherProps := cypher.ToCypherProps(matchKeys, "node.")
serializedNodes := []*SerializedNode{} serializedNodes := []*graph.SerializedNode{}
for _, node := range nodes { for _, node := range nodes {
serializedNodes = append(serializedNodes, node.Serialize()) serializedNodes = append(serializedNodes, node.Serialize())
} }
@@ -148,20 +150,20 @@ func MergeRels(
rtype string, rtype string,
startLabel string, startLabel string,
endLabel string, endLabel string,
matchProvider MatchKeysProvider, matchProvider graph.MatchKeysProvider,
rels []*Relationship, rels []*graph.Relationship,
) (*neo4j.ResultSummary, error) { ) (*neo4j.ResultSummary, error) {
cypherType := ToCypherLabel(rtype) cypherType := cypher.ToCypherLabel(rtype)
startCypherLabel := ToCypherLabel(startLabel) startCypherLabel := cypher.ToCypherLabel(startLabel)
endCypherLabel := ToCypherLabel(endLabel) endCypherLabel := cypher.ToCypherLabel(endLabel)
matchKeys, _ := matchProvider.GetKeys(startLabel) matchKeys, _ := matchProvider.GetKeys(startLabel)
startCypherProps := ToCypherProps(matchKeys, "rel.start.") startCypherProps := cypher.ToCypherProps(matchKeys, "rel.start.")
matchKeys, _ = matchProvider.GetKeys(endLabel) matchKeys, _ = matchProvider.GetKeys(endLabel)
endCypherProps := ToCypherProps(matchKeys, "rel.end.") endCypherProps := cypher.ToCypherProps(matchKeys, "rel.end.")
serializedRels := []*SerializedRel{} serializedRels := []*graph.SerializedRel{}
for _, rel := range rels { for _, rel := range rels {
serializedRels = append(serializedRels, rel.Serialize()) serializedRels = append(serializedRels, rel.Serialize())
} }

View File

@@ -1,4 +1,4 @@
package heartwood package graphstore
import ( import (
"context" "context"
@@ -10,10 +10,13 @@ func ConnectNeo4j(ctx context.Context, uri, user, password string) (neo4j.Driver
driver, err := neo4j.NewDriver( driver, err := neo4j.NewDriver(
uri, uri,
neo4j.BasicAuth(user, password, "")) neo4j.BasicAuth(user, password, ""))
if err != nil {
return nil, err
}
err = driver.VerifyConnectivity(ctx) err = driver.VerifyConnectivity(ctx)
if err != nil { if err != nil {
return driver, err return nil, err
} }
return driver, nil return driver, nil

42
graphstore/schema.go Normal file
View File

@@ -0,0 +1,42 @@
package graphstore
import (
"context"
"github.com/neo4j/neo4j-go-driver/v6/neo4j"
)
// SetNeo4jSchema ensures that the necessary indexes and constraints exist in
// the database
func SetNeo4jSchema(ctx context.Context, driver neo4j.Driver) error {
schemaQueries := []string{
`CREATE CONSTRAINT user_pubkey IF NOT EXISTS
FOR (n:User) REQUIRE n.pubkey IS UNIQUE`,
`CREATE INDEX user_pubkey IF NOT EXISTS
FOR (n:User) ON (n.pubkey)`,
`CREATE INDEX event_id IF NOT EXISTS
FOR (n:Event) ON (n.id)`,
`CREATE INDEX event_kind IF NOT EXISTS
FOR (n:Event) ON (n.kind)`,
`CREATE INDEX tag_name_value IF NOT EXISTS
FOR (n:Tag) ON (n.name, n.value)`,
}
// Create indexes and constraints
for _, query := range schemaQueries {
_, err := neo4j.ExecuteQuery(ctx, driver,
query,
nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,37 +1,38 @@
package heartwood package heartwood
import ( import (
"git.wisehodl.dev/jay/go-heartwood/graph"
roots "git.wisehodl.dev/jay/go-roots/events" roots "git.wisehodl.dev/jay/go-roots/events"
) )
func EventToSubgraph(e roots.Event, exp ExpanderRegistry) *Subgraph { func EventToSubgraph(e roots.Event, exp ExpanderRegistry) *graph.Subgraph {
subgraph := NewSubgraph() subgraph := graph.NewSubgraph()
// Create Event node // Create Event node
eventNode := NewEventNode(e.ID) eventNode := graph.NewEventNode(e.ID)
eventNode.Props["created_at"] = e.CreatedAt eventNode.Props["created_at"] = e.CreatedAt
eventNode.Props["kind"] = e.Kind eventNode.Props["kind"] = e.Kind
eventNode.Props["content"] = e.Content eventNode.Props["content"] = e.Content
// Create User node // Create User node
userNode := NewUserNode(e.PubKey) userNode := graph.NewUserNode(e.PubKey)
// Create SIGNED rel // Create SIGNED rel
signedRel := NewSignedRel(userNode, eventNode, nil) signedRel := graph.NewSignedRel(userNode, eventNode, nil)
// Create Tag nodes // Create Tag nodes
tagNodes := []*Node{} tagNodes := []*graph.Node{}
for _, tag := range e.Tags { for _, tag := range e.Tags {
if !isValidTag(tag) { if !isValidTag(tag) {
continue continue
} }
tagNodes = append(tagNodes, NewTagNode(tag[0], tag[1])) tagNodes = append(tagNodes, graph.NewTagNode(tag[0], tag[1]))
} }
// Create Tag rels // Create Tag rels
tagRels := []*Relationship{} tagRels := []*graph.Relationship{}
for _, tagNode := range tagNodes { for _, tagNode := range tagNodes {
tagRels = append(tagRels, NewTaggedRel(eventNode, tagNode, nil)) tagRels = append(tagRels, graph.NewTaggedRel(eventNode, tagNode, nil))
} }
// Populate subgraph // Populate subgraph

View File

@@ -2,6 +2,7 @@ package heartwood
import ( import (
"fmt" "fmt"
"git.wisehodl.dev/jay/go-heartwood/graph"
roots "git.wisehodl.dev/jay/go-roots/events" roots "git.wisehodl.dev/jay/go-roots/events"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"reflect" "reflect"
@@ -21,21 +22,21 @@ var static = roots.Event{
Content: "hello", Content: "hello",
} }
func newFullEventNode(id string, createdAt, kind int, content string) *Node { func newFullEventNode(id string, createdAt, kind int, content string) *graph.Node {
n := NewEventNode(id) n := graph.NewEventNode(id)
n.Props["created_at"] = createdAt n.Props["created_at"] = createdAt
n.Props["kind"] = kind n.Props["kind"] = kind
n.Props["content"] = content n.Props["content"] = content
return n return n
} }
func baseSubgraph(eventID, pubkey string) (*Subgraph, *Node, *Node) { func baseSubgraph(eventID, pubkey string) (*graph.Subgraph, *graph.Node, *graph.Node) {
s := NewSubgraph() s := graph.NewSubgraph()
eventNode := newFullEventNode(eventID, static.CreatedAt, static.Kind, static.Content) eventNode := newFullEventNode(eventID, static.CreatedAt, static.Kind, static.Content)
userNode := NewUserNode(pubkey) userNode := graph.NewUserNode(pubkey)
s.AddNode(eventNode) s.AddNode(eventNode)
s.AddNode(userNode) s.AddNode(userNode)
s.AddRel(NewSignedRel(userNode, eventNode, nil)) s.AddRel(graph.NewSignedRel(userNode, eventNode, nil))
return s, eventNode, userNode return s, eventNode, userNode
} }
@@ -43,7 +44,7 @@ func TestEventToSubgraph(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
event roots.Event event roots.Event
expected *Subgraph expected *graph.Subgraph
}{ }{
{ {
name: "bare event", name: "bare event",
@@ -51,7 +52,7 @@ func TestEventToSubgraph(t *testing.T) {
ID: ids["a"], PubKey: ids["b"], ID: ids["a"], PubKey: ids["b"],
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, _, _ := baseSubgraph(ids["a"], ids["b"]) s, _, _ := baseSubgraph(ids["a"], ids["b"])
return s return s
}(), }(),
@@ -63,11 +64,11 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"t", "bitcoin"}}, Tags: []roots.Tag{{"t", "bitcoin"}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, eventNode, _ := baseSubgraph(ids["a"], ids["b"]) s, eventNode, _ := baseSubgraph(ids["a"], ids["b"])
tagNode := NewTagNode("t", "bitcoin") tagNode := graph.NewTagNode("t", "bitcoin")
s.AddNode(tagNode) s.AddNode(tagNode)
s.AddRel(NewTaggedRel(eventNode, tagNode, nil)) s.AddRel(graph.NewTaggedRel(eventNode, tagNode, nil))
return s return s
}(), }(),
}, },
@@ -78,7 +79,7 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"t"}}, Tags: []roots.Tag{{"t"}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, _, _ := baseSubgraph(ids["a"], ids["b"]) s, _, _ := baseSubgraph(ids["a"], ids["b"])
return s return s
}(), }(),
@@ -90,14 +91,14 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"e", ids["c"]}}, Tags: []roots.Tag{{"e", ids["c"]}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, eventNode, _ := baseSubgraph(ids["a"], ids["b"]) s, eventNode, _ := baseSubgraph(ids["a"], ids["b"])
tagNode := NewTagNode("e", ids["c"]) tagNode := graph.NewTagNode("e", ids["c"])
referencedEvent := NewEventNode(ids["c"]) referencedEvent := graph.NewEventNode(ids["c"])
s.AddNode(tagNode) s.AddNode(tagNode)
s.AddNode(referencedEvent) s.AddNode(referencedEvent)
s.AddRel(NewTaggedRel(eventNode, tagNode, nil)) s.AddRel(graph.NewTaggedRel(eventNode, tagNode, nil))
s.AddRel(NewReferencesEventRel(tagNode, referencedEvent, nil)) s.AddRel(graph.NewReferencesEventRel(tagNode, referencedEvent, nil))
return s return s
}(), }(),
}, },
@@ -108,11 +109,11 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"e", "notvalid"}}, Tags: []roots.Tag{{"e", "notvalid"}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, eventNode, _ := baseSubgraph(ids["a"], ids["b"]) s, eventNode, _ := baseSubgraph(ids["a"], ids["b"])
tagNode := NewTagNode("e", "notvalid") tagNode := graph.NewTagNode("e", "notvalid")
s.AddNode(tagNode) s.AddNode(tagNode)
s.AddRel(NewTaggedRel(eventNode, tagNode, nil)) s.AddRel(graph.NewTaggedRel(eventNode, tagNode, nil))
return s return s
}(), }(),
}, },
@@ -123,14 +124,14 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"p", ids["d"]}}, Tags: []roots.Tag{{"p", ids["d"]}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, eventNode, _ := baseSubgraph(ids["a"], ids["b"]) s, eventNode, _ := baseSubgraph(ids["a"], ids["b"])
tagNode := NewTagNode("p", ids["d"]) tagNode := graph.NewTagNode("p", ids["d"])
referencedUser := NewUserNode(ids["d"]) referencedUser := graph.NewUserNode(ids["d"])
s.AddNode(tagNode) s.AddNode(tagNode)
s.AddNode(referencedUser) s.AddNode(referencedUser)
s.AddRel(NewTaggedRel(eventNode, tagNode, nil)) s.AddRel(graph.NewTaggedRel(eventNode, tagNode, nil))
s.AddRel(NewReferencesUserRel(tagNode, referencedUser, nil)) s.AddRel(graph.NewReferencesUserRel(tagNode, referencedUser, nil))
return s return s
}(), }(),
}, },
@@ -141,11 +142,11 @@ func TestEventToSubgraph(t *testing.T) {
CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content, CreatedAt: static.CreatedAt, Kind: static.Kind, Content: static.Content,
Tags: []roots.Tag{{"p", "notvalid"}}, Tags: []roots.Tag{{"p", "notvalid"}},
}, },
expected: func() *Subgraph { expected: func() *graph.Subgraph {
s, eventNode, _ := baseSubgraph(ids["a"], ids["b"]) s, eventNode, _ := baseSubgraph(ids["a"], ids["b"])
tagNode := NewTagNode("p", "notvalid") tagNode := graph.NewTagNode("p", "notvalid")
s.AddNode(tagNode) s.AddNode(tagNode)
s.AddRel(NewTaggedRel(eventNode, tagNode, nil)) s.AddRel(graph.NewTaggedRel(eventNode, tagNode, nil))
return s return s
}(), }(),
}, },
@@ -163,7 +164,7 @@ func TestEventToSubgraph(t *testing.T) {
// helpers // helpers
func nodesEqual(expected, got *Node) error { func nodesEqual(expected, got *graph.Node) error {
// Compare label counts // Compare label counts
if expected.Labels.Length() != got.Labels.Length() { if expected.Labels.Length() != got.Labels.Length() {
return fmt.Errorf( return fmt.Errorf(
@@ -186,7 +187,7 @@ func nodesEqual(expected, got *Node) error {
return nil return nil
} }
func relsEqual(expected, got *Relationship) error { func relsEqual(expected, got *graph.Relationship) error {
// Compare type // Compare type
if expected.Type != got.Type { if expected.Type != got.Type {
return fmt.Errorf("type: expected %q, got %q", expected.Type, got.Type) return fmt.Errorf("type: expected %q, got %q", expected.Type, got.Type)
@@ -208,7 +209,7 @@ func relsEqual(expected, got *Relationship) error {
return nil return nil
} }
func propsEqual(expected, got Properties) error { func propsEqual(expected, got graph.Properties) error {
if len(expected) != len(got) { if len(expected) != len(got) {
return fmt.Errorf( return fmt.Errorf(
"number of props does not match. expected %d, got %d", "number of props does not match. expected %d, got %d",
@@ -227,13 +228,13 @@ func propsEqual(expected, got Properties) error {
return nil return nil
} }
func assertSubgraphsEqual(t *testing.T, expected, got *Subgraph) { func assertSubgraphsEqual(t *testing.T, expected, got *graph.Subgraph) {
t.Helper() t.Helper()
gotNodes := make([]*Node, len(got.Nodes())) gotNodes := make([]*graph.Node, len(got.Nodes()))
copy(gotNodes, got.Nodes()) copy(gotNodes, got.Nodes())
gotRels := make([]*Relationship, len(got.Rels())) gotRels := make([]*graph.Relationship, len(got.Rels()))
copy(gotRels, got.Rels()) copy(gotRels, got.Rels())
for _, expectedNode := range expected.Nodes() { for _, expectedNode := range expected.Nodes() {