2023-01-20 15:55:44 +00:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
|
|
|
"container/list"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
type tracker struct {
|
2023-03-16 11:57:57 +00:00
|
|
|
// Nodes encountered in current path during the recursive traversal. Used to
|
2023-01-20 15:55:44 +00:00
|
|
|
// check for cycles
|
2023-03-16 11:57:57 +00:00
|
|
|
seenNodes map[interface{}]struct{}
|
2023-01-20 15:55:44 +00:00
|
|
|
|
2023-03-16 11:57:57 +00:00
|
|
|
// List of node names encountered in order in current path during the recursive traversal.
|
2023-01-20 15:55:44 +00:00
|
|
|
// Used to hydrate errors with path to the exact node where error occured.
|
|
|
|
//
|
2023-03-16 11:57:57 +00:00
|
|
|
// NOTE: node and node names can be the same
|
|
|
|
listOfNodes *list.List
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newTracker() *tracker {
|
|
|
|
return &tracker{
|
2023-03-16 11:57:57 +00:00
|
|
|
seenNodes: map[interface{}]struct{}{},
|
|
|
|
listOfNodes: list.New(),
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-16 11:57:57 +00:00
|
|
|
func (t *tracker) errWithTrace(prefix string, initTrace string) error {
|
|
|
|
traceString := initTrace
|
|
|
|
curr := t.listOfNodes.Front()
|
2023-01-20 15:55:44 +00:00
|
|
|
for curr != nil {
|
|
|
|
if curr.Value.(string) != "" {
|
|
|
|
traceString += " -> " + curr.Value.(string)
|
|
|
|
}
|
|
|
|
curr = curr.Next()
|
|
|
|
}
|
2023-03-16 11:57:57 +00:00
|
|
|
return fmt.Errorf(prefix + ". traversal trace: " + traceString)
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 11:57:57 +00:00
|
|
|
func (t *tracker) hasCycle(node interface{}) bool {
|
|
|
|
_, ok := t.seenNodes[node]
|
2023-01-20 15:55:44 +00:00
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2023-03-16 11:57:57 +00:00
|
|
|
func (t *tracker) push(node interface{}, name string) {
|
|
|
|
t.seenNodes[node] = struct{}{}
|
|
|
|
t.listOfNodes.PushBack(name)
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 11:57:57 +00:00
|
|
|
func (t *tracker) pop(nodeType interface{}) {
|
|
|
|
back := t.listOfNodes.Back()
|
|
|
|
t.listOfNodes.Remove(back)
|
|
|
|
delete(t.seenNodes, nodeType)
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|