- Add complete domain layer: Note, Vault, WikiLink, Tag, Frontmatter, Graph entities - Implement repository interfaces for data access abstraction - Create comprehensive configuration system with YAML and env support - Add CLI entry point with signal handling and graceful shutdown - Fix mermaid diagram syntax in design.md (array notation) - Add CLAUDE.md for development guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
117 lines
2.1 KiB
Go
117 lines
2.1 KiB
Go
package domain
|
|
|
|
import "sync"
|
|
|
|
type Graph struct {
|
|
adjacencyList map[string]map[string]bool
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
func NewGraph() *Graph {
|
|
return &Graph{
|
|
adjacencyList: make(map[string]map[string]bool),
|
|
}
|
|
}
|
|
|
|
func (g *Graph) AddEdge(from, to string) {
|
|
g.mutex.Lock()
|
|
defer g.mutex.Unlock()
|
|
|
|
if g.adjacencyList[from] == nil {
|
|
g.adjacencyList[from] = make(map[string]bool)
|
|
}
|
|
g.adjacencyList[from][to] = true
|
|
}
|
|
|
|
func (g *Graph) RemoveEdge(from, to string) {
|
|
g.mutex.Lock()
|
|
defer g.mutex.Unlock()
|
|
|
|
if g.adjacencyList[from] != nil {
|
|
delete(g.adjacencyList[from], to)
|
|
if len(g.adjacencyList[from]) == 0 {
|
|
delete(g.adjacencyList, from)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *Graph) GetOutlinks(path string) []string {
|
|
g.mutex.RLock()
|
|
defer g.mutex.RUnlock()
|
|
|
|
var outlinks []string
|
|
if targets, exists := g.adjacencyList[path]; exists {
|
|
for target := range targets {
|
|
outlinks = append(outlinks, target)
|
|
}
|
|
}
|
|
return outlinks
|
|
}
|
|
|
|
func (g *Graph) GetBacklinks(path string) []string {
|
|
g.mutex.RLock()
|
|
defer g.mutex.RUnlock()
|
|
|
|
var backlinks []string
|
|
for source, targets := range g.adjacencyList {
|
|
if targets[path] {
|
|
backlinks = append(backlinks, source)
|
|
}
|
|
}
|
|
return backlinks
|
|
}
|
|
|
|
func (g *Graph) HasEdge(from, to string) bool {
|
|
g.mutex.RLock()
|
|
defer g.mutex.RUnlock()
|
|
|
|
if targets, exists := g.adjacencyList[from]; exists {
|
|
return targets[to]
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (g *Graph) RemoveNode(path string) {
|
|
g.mutex.Lock()
|
|
defer g.mutex.Unlock()
|
|
|
|
delete(g.adjacencyList, path)
|
|
|
|
for source, targets := range g.adjacencyList {
|
|
delete(targets, path)
|
|
if len(targets) == 0 {
|
|
delete(g.adjacencyList, source)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *Graph) GetAllNodes() []string {
|
|
g.mutex.RLock()
|
|
defer g.mutex.RUnlock()
|
|
|
|
nodeSet := make(map[string]bool)
|
|
|
|
for source := range g.adjacencyList {
|
|
nodeSet[source] = true
|
|
}
|
|
|
|
for _, targets := range g.adjacencyList {
|
|
for target := range targets {
|
|
nodeSet[target] = true
|
|
}
|
|
}
|
|
|
|
var nodes []string
|
|
for node := range nodeSet {
|
|
nodes = append(nodes, node)
|
|
}
|
|
|
|
return nodes
|
|
}
|
|
|
|
func (g *Graph) Clear() {
|
|
g.mutex.Lock()
|
|
defer g.mutex.Unlock()
|
|
|
|
g.adjacencyList = make(map[string]map[string]bool)
|
|
} |