defmodule RedisGraph.Node do @moduledoc """ A Node member of a Graph. Nodes have an alias which uniquely identifies them in a Graph. Nodes must have an alias. When alias is not provided on initialization, a random alias will be set on the Node. Nodes may optionally have a list of labels which is analogous to a type definition. Nodes can be queried based on their labels, e.g. ``person`` or ``place`` or ``food``. Nodes may optionally have properties as well, which is a map of values associated with the entity. These properties can be returned by database queries. Nodes which are created as the result of a passed query to the graph database through `RedisGraph.QueryResult` will also have numeric ids which are internal to the graph in the database. """ alias RedisGraph.Util @type t() :: %__MODULE__{ id: integer(), alias: atom(), labels: [String.t()], properties: %{} } defstruct [:id, :alias, labels: [], properties: %{}] @doc """ Creates a new Node with default arguments. ## Example ``` alias RedisGraph.{Node} # create a Node bob = Node.new() ``` """ @spec new() :: t() def new() do new(%{}) end @doc """ Creates a new Node from provided argument. ## Example ``` alias RedisGraph.{Node} # create a Node bob = Node.new(%{ alias: :n, labels: ["person"], properties: %{ name: "Bob Thomsen", age: 22 } }) ``` """ @spec new(map()) :: t() def new(map) when is_map(map) do node = struct(__MODULE__, map) if(is_nil(node.alias), do: set_alias_if_nil(node), else: node) end @doc "Sets the node's alias to atom if it is `nil`." @spec set_alias_if_nil(t()) :: t() def set_alias_if_nil(node) do if is_nil(node.alias) do alias = Util.random_string() |> String.to_atom() %{node | alias: alias} else node end end @doc """ Compare two Nodes with respect to equality. Comparison logic: * if ids differ then returns ``false`` * if aliases differ then returns ``false`` * if labels differ then returns ``false`` * if properties differ then returns ``false`` * otherwise returns ``true`` """ @spec compare(t(), t()) :: boolean() def compare(left, right) do cond do left.id != right.id -> false left.alias != right.alias -> false length(left.labels) != length(right.labels) -> false left.labels != right.labels -> false map_size(left.properties) != map_size(right.properties) -> false not Map.equal?(left.properties, right.properties) -> false true -> true end end end