Rename sort keys to batch keys.

This commit is contained in:
Jay
2026-03-03 16:16:24 -05:00
parent e9e153c9a1
commit 4114b4c02a
4 changed files with 56 additions and 56 deletions

View File

@@ -31,12 +31,12 @@ type MatchKeysProvider interface {
GetKeys(label string) ([]string, bool) GetKeys(label string) ([]string, bool)
} }
// MatchKeys is a simple implementation of the MatchKeysProvider interface. // SimpleMatchKeys is a simple implementation of the MatchKeysProvider interface.
type MatchKeys struct { type SimpleMatchKeys struct {
Keys map[string][]string Keys map[string][]string
} }
func (p *MatchKeys) GetLabels() []string { func (p *SimpleMatchKeys) GetLabels() []string {
labels := []string{} labels := []string{}
for l := range p.Keys { for l := range p.Keys {
labels = append(labels, l) labels = append(labels, l)
@@ -44,7 +44,7 @@ func (p *MatchKeys) GetLabels() []string {
return labels return labels
} }
func (p *MatchKeys) GetKeys(label string) ([]string, bool) { func (p *SimpleMatchKeys) 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 {
@@ -216,9 +216,9 @@ func (s *Subgraph) NodesByLabel(label string) []*Node {
// StructuredSubgraph is a structured collection of nodes and relationships for // StructuredSubgraph is a structured collection of nodes and relationships for
// the purpose of conducting batch operations. // the purpose of conducting batch operations.
type StructuredSubgraph struct { type StructuredSubgraph struct {
// A map of grouped nodes, sorted by their label combinations. // A map of grouped nodes, batched by their label combinations.
nodes map[string][]*Node nodes map[string][]*Node
// A map of grouped relationships, sorted by their type and related node // A map of grouped relationships, batched by their type and related node
// labels. // labels.
rels map[string][]*Relationship rels map[string][]*Relationship
// Provides node property keys used to match nodes with given labels in the // Provides node property keys used to match nodes with given labels in the
@@ -236,7 +236,7 @@ func NewStructuredSubgraph(matchProvider MatchKeysProvider) *StructuredSubgraph
} }
} }
// AddNode sorts a node into the subgraph. // AddNode adds a node into the subgraph.
func (s *StructuredSubgraph) AddNode(node *Node) error { func (s *StructuredSubgraph) AddNode(node *Node) error {
// Verify that the node has defined match property values. // Verify that the node has defined match property values.
@@ -245,20 +245,20 @@ func (s *StructuredSubgraph) AddNode(node *Node) error {
return fmt.Errorf("invalid node: %s", err) return fmt.Errorf("invalid node: %s", err)
} }
// Determine the node's sort key. // Determine the node's batch key.
sortKey := createNodeSortKey(matchLabel, node.Labels.ToArray()) batchKey := createNodeBatchKey(matchLabel, node.Labels.ToArray())
if _, exists := s.nodes[sortKey]; !exists { if _, exists := s.nodes[batchKey]; !exists {
s.nodes[sortKey] = []*Node{} s.nodes[batchKey] = []*Node{}
} }
// Add the node to the subgraph. // Add the node to the subgraph.
s.nodes[sortKey] = append(s.nodes[sortKey], node) s.nodes[batchKey] = append(s.nodes[batchKey], node)
return nil return nil
} }
// AddRel sorts a relationship into the subgraph. // AddRel adds a relationship into the subgraph.
func (s *StructuredSubgraph) AddRel(rel *Relationship) error { func (s *StructuredSubgraph) AddRel(rel *Relationship) error {
// Verify that the start node has defined match property values. // Verify that the start node has defined match property values.
@@ -273,25 +273,25 @@ func (s *StructuredSubgraph) AddRel(rel *Relationship) error {
return fmt.Errorf("invalid end node: %s", err) return fmt.Errorf("invalid end node: %s", err)
} }
// Determine the relationship's sort key. // Determine the relationship's batch key.
sortKey := createRelSortKey(rel.Type, startLabel, endLabel) batchKey := createRelBatchKey(rel.Type, startLabel, endLabel)
if _, exists := s.rels[sortKey]; !exists { if _, exists := s.rels[batchKey]; !exists {
s.rels[sortKey] = []*Relationship{} s.rels[batchKey] = []*Relationship{}
} }
// Add the relationship to the subgraph. // Add the relationship to the subgraph.
s.rels[sortKey] = append(s.rels[sortKey], rel) s.rels[batchKey] = append(s.rels[batchKey], rel)
return nil return nil
} }
// GetNodes returns the nodes grouped under the given sort key. // GetNodes returns the nodes grouped under the given batch key.
func (s *StructuredSubgraph) GetNodes(nodeKey string) []*Node { func (s *StructuredSubgraph) GetNodes(nodeKey string) []*Node {
return s.nodes[nodeKey] return s.nodes[nodeKey]
} }
// GetRels returns the rels grouped under the given sort key. // GetRels returns the rels grouped under the given batch key.
func (s *StructuredSubgraph) GetRels(relKey string) []*Relationship { func (s *StructuredSubgraph) GetRels(relKey string) []*Relationship {
return s.rels[relKey] return s.rels[relKey]
} }
@@ -318,7 +318,7 @@ func (s *StructuredSubgraph) RelCount() int {
return count return count
} }
// NodeKeys returns the list of node sort keys in the subgraph. // NodeKeys returns the list of node batch keys in the subgraph.
func (s *StructuredSubgraph) NodeKeys() []string { func (s *StructuredSubgraph) NodeKeys() []string {
keys := []string{} keys := []string{}
for l := range s.nodes { for l := range s.nodes {
@@ -327,7 +327,7 @@ func (s *StructuredSubgraph) NodeKeys() []string {
return keys return keys
} }
// RelKeys returns the list of relationship sort keys in the subgraph. // RelKeys returns the list of relationship batch keys in the subgraph.
func (s *StructuredSubgraph) RelKeys() []string { func (s *StructuredSubgraph) RelKeys() []string {
keys := []string{} keys := []string{}
for t := range s.rels { for t := range s.rels {
@@ -336,38 +336,38 @@ func (s *StructuredSubgraph) RelKeys() []string {
return keys return keys
} }
// createNodeSortKey returns the serialized node labels for sorting. // createNodeBatchKey returns the serialized node labels for batching.
func createNodeSortKey(matchLabel string, labels []string) string { func createNodeBatchKey(matchLabel string, labels []string) string {
sort.Strings(labels) sort.Strings(labels)
serializedLabels := strings.Join(labels, ",") serializedLabels := strings.Join(labels, ",")
return fmt.Sprintf("%s:%s", matchLabel, serializedLabels) return fmt.Sprintf("%s:%s", matchLabel, serializedLabels)
} }
// createRelSortKey returns the serialized relationship type and start/end node // createRelBatchKey returns the serialized relationship type and start/end node
// labels for sorting. // labels for batching.
func createRelSortKey( func createRelBatchKey(
rtype string, startLabel string, endLabel string) string { rtype string, startLabel string, endLabel string) string {
return strings.Join([]string{rtype, startLabel, endLabel}, ",") return strings.Join([]string{rtype, startLabel, endLabel}, ",")
} }
// DeserializeNodeKey returns the list of node labels from the serialized sort // DeserializeNodeBatchKey returns the list of node labels from the serialized batch
// key. // key.
func DeserializeNodeKey(sortKey string) (string, []string, error) { func DeserializeNodeBatchKey(batchKey string) (string, []string, error) {
parts := strings.Split(sortKey, ":") parts := strings.Split(batchKey, ":")
if len(parts) != 2 { if len(parts) != 2 {
return "", nil, fmt.Errorf("invalid node sort key: %s", sortKey) return "", nil, fmt.Errorf("invalid node batch key: %s", batchKey)
} }
matchLabel, serializedLabels := parts[0], parts[1] matchLabel, serializedLabels := parts[0], parts[1]
labels := strings.Split(serializedLabels, ",") labels := strings.Split(serializedLabels, ",")
return matchLabel, labels, nil return matchLabel, labels, nil
} }
// DeserializeRelKey returns the relationship type, start node label, and end // DeserializeRelBatchKey returns the relationship type, start node label, and end
// node label from the serialized sort key. Panics if the sort key is invalid. // node label from the serialized batch key. Panics if the batch key is invalid.
func DeserializeRelKey(sortKey string) (string, string, string, error) { func DeserializeRelBatchKey(batchKey string) (string, string, string, error) {
parts := strings.Split(sortKey, ",") parts := strings.Split(batchKey, ",")
if len(parts) != 3 { if len(parts) != 3 {
return "", "", "", fmt.Errorf("invalid relationship sort key: %s", sortKey) return "", "", "", fmt.Errorf("invalid relationship batch key: %s", batchKey)
} }
rtype, startLabel, endLabel := parts[0], parts[1], parts[2] rtype, startLabel, endLabel := parts[0], parts[1], parts[2]
return rtype, startLabel, endLabel, nil return rtype, startLabel, endLabel, nil

View File

@@ -6,7 +6,7 @@ import (
) )
func TestMatchKeys(t *testing.T) { func TestMatchKeys(t *testing.T) {
matchKeys := &MatchKeys{ matchKeys := &SimpleMatchKeys{
Keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Event": {"id"}, "Event": {"id"},
@@ -34,34 +34,34 @@ func TestMatchKeys(t *testing.T) {
}) })
} }
func TestNodeSortKey(t *testing.T) { func TestNodeBatchKey(t *testing.T) {
matchLabel := "Event" matchLabel := "Event"
labels := []string{"Event", "AddressableEvent"} labels := []string{"Event", "AddressableEvent"}
// labels should be sorted by key generator // labels should be batched by key generator
expectedKey := "Event:AddressableEvent,Event" expectedKey := "Event:AddressableEvent,Event"
// Test Serialization // Test Serialization
sortKey := createNodeSortKey(matchLabel, labels) batchKey := createNodeBatchKey(matchLabel, labels)
assert.Equal(t, expectedKey, sortKey) assert.Equal(t, expectedKey, batchKey)
// Test Deserialization // Test Deserialization
returnedMatchLabel, returnedLabels, err := DeserializeNodeKey(sortKey) returnedMatchLabel, returnedLabels, err := DeserializeNodeBatchKey(batchKey)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, matchLabel, returnedMatchLabel) assert.Equal(t, matchLabel, returnedMatchLabel)
assert.ElementsMatch(t, labels, returnedLabels) assert.ElementsMatch(t, labels, returnedLabels)
} }
func TestRelSortKey(t *testing.T) { func TestRelBatchKey(t *testing.T) {
rtype, startLabel, endLabel := "SIGNED", "User", "Event" rtype, startLabel, endLabel := "SIGNED", "User", "Event"
expectedKey := "SIGNED,User,Event" expectedKey := "SIGNED,User,Event"
// Test Serialization // Test Serialization
sortKey := createRelSortKey(rtype, startLabel, endLabel) batchKey := createRelBatchKey(rtype, startLabel, endLabel)
assert.Equal(t, expectedKey, sortKey) assert.Equal(t, expectedKey, batchKey)
// Test Deserialization // Test Deserialization
returnedRtype, returnedStartLabel, returnedEndLabel, err := DeserializeRelKey(sortKey) returnedRtype, returnedStartLabel, returnedEndLabel, err := DeserializeRelBatchKey(batchKey)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, rtype, returnedRtype) assert.Equal(t, rtype, returnedRtype)
assert.Equal(t, startLabel, returnedStartLabel) assert.Equal(t, startLabel, returnedStartLabel)
@@ -69,7 +69,7 @@ func TestRelSortKey(t *testing.T) {
} }
func TestMatchProps(t *testing.T) { func TestMatchProps(t *testing.T) {
matchKeys := &MatchKeys{ matchKeys := &SimpleMatchKeys{
Keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Event": {"id"}, "Event": {"id"},
@@ -133,7 +133,7 @@ func TestMatchProps(t *testing.T) {
} }
func TestStructuredSubgraphAddNode(t *testing.T) { func TestStructuredSubgraphAddNode(t *testing.T) {
matchKeys := NewMatchKeys() matchKeys := NewSimpleMatchKeys()
subgraph := NewStructuredSubgraph(matchKeys) subgraph := NewStructuredSubgraph(matchKeys)
node := NewEventNode("abc123") node := NewEventNode("abc123")
@@ -145,7 +145,7 @@ func TestStructuredSubgraphAddNode(t *testing.T) {
} }
func TestStructuredSubgraphAddNodeInvalid(t *testing.T) { func TestStructuredSubgraphAddNodeInvalid(t *testing.T) {
matchKeys := NewMatchKeys() matchKeys := NewSimpleMatchKeys()
subgraph := NewStructuredSubgraph(matchKeys) subgraph := NewStructuredSubgraph(matchKeys)
node := NewNode("Event", Properties{}) node := NewNode("Event", Properties{})
@@ -156,7 +156,7 @@ func TestStructuredSubgraphAddNodeInvalid(t *testing.T) {
} }
func TestStructuredSubgraphAddRel(t *testing.T) { func TestStructuredSubgraphAddRel(t *testing.T) {
matchKeys := NewMatchKeys() matchKeys := NewSimpleMatchKeys()
subgraph := NewStructuredSubgraph(matchKeys) subgraph := NewStructuredSubgraph(matchKeys)
userNode := NewUserNode("pubkey1") userNode := NewUserNode("pubkey1")

View File

@@ -11,8 +11,8 @@ import (
// Schema Match Keys // Schema Match Keys
// ======================================== // ========================================
func NewMatchKeys() *MatchKeys { func NewSimpleMatchKeys() *SimpleMatchKeys {
return &MatchKeys{ return &SimpleMatchKeys{
Keys: map[string][]string{ Keys: map[string][]string{
"User": {"pubkey"}, "User": {"pubkey"},
"Relay": {"url"}, "Relay": {"url"},

View File

@@ -15,7 +15,7 @@ func MergeSubgraph(
) ([]neo4j.ResultSummary, error) { ) ([]neo4j.ResultSummary, error) {
// Validate subgraph // Validate subgraph
for _, nodeKey := range subgraph.NodeKeys() { for _, nodeKey := range subgraph.NodeKeys() {
matchLabel, _, err := graph.DeserializeNodeKey(nodeKey) matchLabel, _, err := graph.DeserializeNodeBatchKey(nodeKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -27,7 +27,7 @@ func MergeSubgraph(
} }
for _, relKey := range subgraph.RelKeys() { for _, relKey := range subgraph.RelKeys() {
_, startLabel, endLabel, err := graph.DeserializeRelKey(relKey) _, startLabel, endLabel, err := graph.DeserializeRelBatchKey(relKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -51,7 +51,7 @@ func MergeSubgraph(
var resultSummaries []neo4j.ResultSummary var resultSummaries []neo4j.ResultSummary
for _, nodeKey := range subgraph.NodeKeys() { for _, nodeKey := range subgraph.NodeKeys() {
matchLabel, labels, _ := graph.DeserializeNodeKey(nodeKey) matchLabel, labels, _ := graph.DeserializeNodeBatchKey(nodeKey)
nodeResultSummary, err := MergeNodes( nodeResultSummary, err := MergeNodes(
ctx, tx, ctx, tx,
matchLabel, matchLabel,
@@ -68,7 +68,7 @@ func MergeSubgraph(
} }
for _, relKey := range subgraph.RelKeys() { for _, relKey := range subgraph.RelKeys() {
rtype, startLabel, endLabel, _ := graph.DeserializeRelKey(relKey) rtype, startLabel, endLabel, _ := graph.DeserializeRelBatchKey(relKey)
relResultSummary, err := MergeRels( relResultSummary, err := MergeRels(
ctx, tx, ctx, tx,
rtype, rtype,