Current section
Files
Jump to
Current section
Files
lib/redis_graph/graph.ex
defmodule RedisGraph.Graph do
@moduledoc """
A Graph consisting of `RedisGraph.Node`s and `RedisGraph.Edge`s.
A name is required for each graph.
Construct graphs by adding `RedisGraph.Node`s followed
by `RedisGraph.Edge`s which relate existing nodes.
If a node does not have an alias, a random alias will
be created for it when adding to a `RedisGraph.Graph`.
Edges cannot be added unless both the source node and
destination node aliases already exist in the graph.
"""
alias RedisGraph.Edge
alias RedisGraph.Node
@type t() :: %__MODULE__{
name: String.t(),
nodes: %{optional(String.t()) => Node.t()},
edges: list(Edge.t())
}
@enforce_keys [:name]
defstruct [
:name,
nodes: %{},
edges: []
]
@doc """
Create a graph from a map.
## Example
```
alias RedisGraph.{Node, Edge, Graph, QueryResult}
# Create a graph
graph = Graph.new(%{
name: "social"
})
# Create a node
john = Node.new(%{
label: "person",
properties: %{
name: "John Doe",
age: 33,
gender: "male",
status: "single"
}
})
# Add the node to the graph
# The graph and node are returned
# The node may be modified if no alias has been set
# For this reason, nodes should always be added to the graph
# before creating edges between them.
{graph, john} = Graph.add_node(graph, john)
# Create a second node
japan = Node.new(%{
label: "country",
properties: %{
name: "Japan"
}
})
# Add the second node
{graph, japan} = Graph.add_node(graph, japan)
# Create an edge connecting the two nodes
edge = Edge.new(%{
src_node: john,
dest_node: japan,
relation: "visited"
})
# Add the edge to the graph
# If the nodes are not present, an {:error, error} is returned
{:ok, graph} = Graph.add_edge(graph, edge)
```
"""
@spec new(map()) :: t()
def new(map) do
struct(__MODULE__, map)
end
@doc """
Add a `RedisGraph.Node` to a graph.
Creates a random string alias for the Node
if the Node has no alias.
"""
@spec add_node(t(), Node.t()) :: {t(), Node.t()}
def add_node(graph, node) do
node = Node.set_alias_if_nil(node)
{%{graph | nodes: Map.put(graph.nodes, node.alias, node)}, node}
end
@doc """
Add a `RedisGraph.Edge` to a graph.
If the source node or destination node are not part of the
graph, then the edge cannot be added. Uses node aliases
to check graph membership.
"""
@spec add_edge(t(), Edge.t()) :: {:ok, t()} | {:error, any()}
def add_edge(graph, edge) do
cond do
not node_in_graph?(graph, edge.src_node) -> {:error, "source node not in graph"}
not node_in_graph?(graph, edge.dest_node) -> {:error, "destination node not in graph"}
true -> {:ok, %{graph | edges: graph.edges ++ [edge]}}
end
end
defp node_in_graph?(graph, node) do
Map.has_key?(graph.nodes, node.alias)
end
end