Service Contexts
Learn how to avoid naming conflicts and switch between various graph models seamlessly.
We'll cover the following...
We'll cover the following...
Problem
If we import two graph modules, we’ll run into a conflict in our function names.
iex> import NativeGraphNativeGraphiex> import PropertyGraphPropertyGraphiex> list_graphs
This won't do. If we try the commands above in the following terminal, we get a CompileError
:
#--- # Excerpted from "Exploring Graphs with Elixir", # published by The Pragmatic Bookshelf. # Copyrights apply to this code. It may not be used to create training material, # courses, books, articles, and the like. Contact us if you are in doubt. # We make no guarantees that this code is fit for any purpose. # Visit https://pragprog.com/titles/thgraphs for more book information. #--- defmodule PropertyGraph.Service do @behaviour GraphCommons.Service @cypher_delete """ MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r """ @cypher_read """ MATCH (n) OPTIONAL MATCH (n)-[r]-() RETURN DISTINCT n, r """ @cypher_info """ CALL apoc.meta.stats() YIELD labels, labelCount, nodeCount, relCount, relTypeCount """ ## GRAPH def graph_create(graph) do graph_delete() graph_update(graph) end def graph_delete(), do: Bolt.Sips.query!(Bolt.Sips.conn(), @cypher_delete) def graph_read(), do: Bolt.Sips.query!(Bolt.Sips.conn(), @cypher_read) def graph_update(%GraphCommons.Graph{} = graph), do: Bolt.Sips.query!(Bolt.Sips.conn(), graph.data) def graph_info() do {:ok, [stats]} = @cypher_info |> PropertyGraph.new_query() |> query_graph %GraphCommons.Service.GraphInfo{ type: :property, file: "", num_nodes: stats["nodeCount"], num_edges: stats["relCount"], labels: Map.keys(stats["labels"]) } end ## QUERY def query_graph(%GraphCommons.Query{} = query), do: query_graph(query, %{}) def query_graph(%GraphCommons.Query{} = query, params) do :property = query.type Bolt.Sips.query(Bolt.Sips.conn(), query.data, params) |> case do {:ok, response} -> parse_response(response, false) {:error, error} -> {:error, error} end end def query_graph!(%GraphCommons.Query{} = query), do: query_graph!(query, %{}) def query_graph!(%GraphCommons.Query{} = query, params) do :property = query.type Bolt.Sips.query(Bolt.Sips.conn(), query.data, params) |> case do {:ok, response} -> parse_response(response, true) {:error, error} -> raise "! #{inspect error}" end end # # def query_graph!(%GraphCommons.Query{} = query, param \\ %{}) do # :property = query.type # # Bolt.Sips.query(Bolt.Sips.conn(), query.data, param) # |> case do # {:ok, response} -> parse_response(response, false) # {:error, error} -> {:error, error} # end # end # defp parse_response(%Bolt.Sips.Response{} = response, bang) do %Bolt.Sips.Response{type: type} = response case type do r when r in ["r", "rw"] -> %Bolt.Sips.Response{results: results} = response unless bang, do: {:ok, results}, else: results s when s in ["s"] -> %Bolt.Sips.Response{results: results} = response unless bang, do: {:ok, results}, else: results w when w in ["w"] -> %Bolt.Sips.Response{stats: stats} = response unless bang, do: {:ok, stats}, else: stats end end end
Importing the two modules will result in a conflict
Solution
We need to be able to delete any previous graph module import before attempting a new import.
There is a way. Basically, if we do an import, restricting the ...