func (g *Graph) Edges(from string) ([]string, error) {
	var edges []string
	g.lock.RLock()
	if _, ok := g.nodes[from]; !ok {
		return edges, ErrorNodeNotFound
	}
	for to := range g.edges[from] {
		if g.edges[from][to] {
			edges = append(edges, to)
		}
	}
	g.lock.RUnlock()
	return edges, nil
}
Edges returns the keys of nodes that are directly connected to the node
package graph
import (
	"bytes"
	"fmt"
	"sync"
)
var (
	ErrorNodeNotFound = fmt.Errorf("node not found")
	ErrorNodeAlreadyExists = fmt.Errorf("node already exists")
)
type Graph struct {
	lock  sync.RWMutex
	nodes map[string]interface{}
	edges map[string]map[string]bool
}
func New() *Graph {
	return &Graph{
		nodes: make(map[string]interface{}),
		edges: make(map[string]map[string]bool),
	}
}
func (g *Graph) NewNode(key string, value interface{}) error {
	g.lock.Lock()
	defer g.lock.Unlock()
	if _, ok := g.nodes[key]; ok {
		return ErrorNodeAlreadyExists
	}
	g.nodes[key] = value
	g.edges[key] = make(map[string]bool)
	return nil
}
func (g *Graph) Value(key string) (interface{}, error) {
	g.lock.RLock()
	defer g.lock.RUnlock()
	if _, ok := g.nodes[key]; !ok {
		return nil, ErrorNodeNotFound
	}
	value := g.nodes[key]
	return value, nil
}
func (g *Graph) UpdateValue(key string, value interface{}) error {
	g.lock.Lock()
	defer g.lock.Unlock()
	if _, ok := g.nodes[key]; !ok {
		return ErrorNodeNotFound
	}
	g.nodes[key] = value
	return nil
}
func (g *Graph) NewEdge(from, to string) error {
	g.lock.Lock()
	defer g.lock.Unlock()
	if _, ok := g.nodes[from]; !ok {
		return ErrorNodeNotFound
	}
	if _, ok := g.nodes[to]; !ok {
		return ErrorNodeNotFound
	}
	g.edges[from][to] = true
	g.edges[to][from] = true
	return nil
}