/
graph.go
111 lines (99 loc) · 2.99 KB
/
graph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package dsgraph
var walkParallelism = 4
// NodeType specifies different types of qri nodes
type NodeType string
var (
// NtDataset is a holistic reference to a dataset,
// aka the base hash of a dataset
NtDataset = NodeType("dataset")
// NtAbstDataset is the abstract form of a dataset
NtAbstDataset = NodeType("abst_dataset")
// NtMetadata is the dataset.json file in a dataset
NtMetadata = NodeType("metadata")
// NtCommit is the commit.json file in a dataset
NtCommit = NodeType("commit")
// NtData is a dataset's raw data
NtData = NodeType("data")
// NtTransform is the transform.json in a dataset
NtTransform = NodeType("transform")
// NtAbstTransform is the abstract_transform.json in a dataset
NtAbstTransform = NodeType("abst_transform")
// NtStructure is the structure.json in a dataset
NtStructure = NodeType("structure")
// NtAbstStructure is the abstract_structure.json in a dataset
NtAbstStructure = NodeType("abst_structure")
// NtNamespace is the namespace of a single qri repository
NtNamespace = NodeType("namespace")
)
// Node is a typed reference to a path
type Node struct {
Type NodeType
Path string
Links []Link
}
// Equal checks for field-level equality with another Node
func (n Node) Equal(b *Node) bool {
return n.Type == b.Type && n.Path == b.Path
}
// AddLinks is a no-duplicates method for adding one or more links to a node
func (n *Node) AddLinks(links ...Link) {
ADDITIONS:
for _, link := range links {
for _, l := range n.Links {
if link.To.Path == "" || link.Equal(l) {
continue ADDITIONS
}
}
n.Links = append(n.Links, link)
}
}
// TODO - still considering if links need to be typed or not
// type LinkType string
// var (
// LtPrevious = LinkType("previous")
// LtResource = LinkType("resource")
// LtDsData = LinkType("dataset_data")
// LtDsCommit = LinkType("dataset_commit")
// LtAbstStructure = LinkType("abst_structure")
// LtTransform = LinkType("transform")
// LtAbstTransform = LinkType("abst_transform")
// LtNamespaceTip = LinkType("namespace_tip")
// )
// Link is a typed, directional connection from one
// node to another
type Link struct {
// Type LinkType
From, To *Node
}
// Equal checks for field-level equality with another Link
func (a Link) Equal(b Link) bool {
return a.From.Equal(b.From) && a.To.Equal(b.To)
}
// FilterNodeTypes returns a slice of node pointers from a graph that match
// the provided NodeType's
func FilterNodeTypes(graph *Node, nodetypes ...NodeType) (nodes []*Node) {
Walk(graph, 0, func(n *Node) error {
if n != nil {
for _, nt := range nodetypes {
if n.Type == nt {
nodes = append(nodes, n)
break
}
}
}
return nil
})
return
}
// Walk visits node and all descendants with a provided visit function
func Walk(node *Node, depth int, visit func(n *Node) error) error {
if err := visit(node); err != nil {
return err
}
for _, l := range node.Links {
if err := Walk(l.To, depth+1, visit); err != nil {
return err
}
}
return nil
}