Skip to content

Instantly share code, notes, and snippets.

@Fadhil
Created September 20, 2017 11:01
Show Gist options
  • Save Fadhil/5f205587305930b310de8549b44a9ec6 to your computer and use it in GitHub Desktop.
Save Fadhil/5f205587305930b310de8549b44a9ec6 to your computer and use it in GitHub Desktop.
Basic Neo4j + Ecto stuff
# I'm doing something like this to build queries:
@spec match(%Query{}, map, string, map) :: %Query{}
def match(current_query, res_a, rel, res_b)
when is_map(res_a) and is_map(res_b) do
query_string = """
MATCH (#{get_node_var(res_a)}:#{node_name(res_a)} {#{attributes_from_struct(res_a)}})
MATCH (#{get_node_var(res_b)}:#{node_name(res_b)} {#{attributes_from_struct(res_b)}})
WITH #{get_node_var(res_a)}, #{get_node_var(res_b)}
MATCH (#{get_node_var(res_a)})-[rel:#{rel}]->(#{get_node_var(res_b)})
"""
current_query
|> append(query_string)
end
def with(query, node_var) when is_bitstring node_var do
query_string = """
WITH #{node_var}
"""
query
|> append(query_string)
end
def append(query, query_string) do
%{query |
string: query.string <> " " <> query_string
}
end
def return(current_query, node_var) when is_bitstring node_var do
query_string = """
RETURN #{node_var}
"""
current_query
|> append(query_string)
end
# So that I can do stuff like:
iex(10)> query = %Query{} |> Query.match(%User{email: "fadhil.luqman@gmail.com"}, "OWNS", %Organisation{}) |> Query.return(["user", "organisation"])
%Flexcility.Graph.Query{
string: " MATCH (user:User {email: 'fadhil.luqman@gmail.com'})\n MATCH (organisation:Organisation {})\n WITH user, organisation\n MATCH (user)-[rel:OWNS]->(organisation)\n RETURN user, organisation\n"
iex(12)> {:ok, [res]} = Graph.run_query(query.string)
[debug] [#Port<0.15312>] cypher: "MATCH (user:User {email: 'fadhil.luqman@gmail.com'})\n MATCH (organisation:Organisation {})\n WITH user, organisation\n MATCH (user)-[rel:OWNS]->(organisation)\n RETURN user, organisation" - params: %{} - bolt: [success: %{"fields" => ["user", "organisation"]}, record: [[sig: 78, fields: [419, ["User"], %{"email" => "fadhil.luqman@gmail.com", "id" => 4, "name" => "Fadhil", "password_hash" => "$2b$12$b1.dBvf1tgBzQaiMk0nzxOEe/elzkGuLOOicz2.SyPKP1cHhAuFsi", "uuid" => "02a72bb0-996b-11e7-88a7-964f323b1657"}]], [sig: 78, fields: [412, ["Organisation"], %{"id" => 2, "location" => "Wilayah Persekutuan", "name" => "JKR", "subdomain" => "jkr", "uuid" => "bdcb6e12-962d-11e7-88a7-964f323b1657"}]]], success: %{"type" => "r"}]
{:ok,
[%{"organisation" => %Bolt.Sips.Types.Node{id: 412, labels: ["Organisation"],
properties: %{"id" => 2, "location" => "Wilayah Persekutuan",
"name" => "JKR", "subdomain" => "jkr",
"uuid" => "bdcb6e12-962d-11e7-88a7-964f323b1657"}},
"user" => %Bolt.Sips.Types.Node{id: 419, labels: ["User"],
properties: %{"email" => "fadhil.luqman@gmail.com", "id" => 4,
"name" => "Fadhil",
"password_hash" => "$2b$12$b1.dBvf1tgBzQaiMk0nzxOEe/elzkGuLOOicz2.SyPKP1cHhAuFsi",
"uuid" => "02a72bb0-996b-11e7-88a7-964f323b1657"}}}]}
# I've also got a Utils.get_struct function that modifies this into Ecto structs like so (using res from above):
iex(22)> [User, Organisation] |> Enum.map(&(Utils.get_struct(res, &1)))
[%Flexcility.Accounts.User{__meta__: #Ecto.Schema.Metadata<:built, "User">,
email: "fadhil.luqman@gmail.com", id: 4, image: nil, name: "Fadhil",
organisations: #Ecto.Association.NotLoaded<association :organisations is not loaded>,
password_hash: "$2b$12$b1.dBvf1tgBzQaiMk0nzxOEe/elzkGuLOOicz2.SyPKP1cHhAuFsi"},
%Flexcility.Accounts.Organisation{__meta__: #Ecto.Schema.Metadata<:built, "Organisation">,
description: nil, id: 2, location: "Wilayah Persekutuan", name: "JKR",
sites: #Ecto.Association.NotLoaded<association :sites is not loaded>,
subdomain: "jkr"}]
# Where Utils is basically:
def get_struct(map, resource) do
get_changeset(map, resource)
|> Changeset.apply_changes()
end
def get_changeset(map, resource) do
props = map
|> get_properties(resource)
resource.__struct__
|> Changeset.cast(props, resource.__schema__(:fields))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment