Module: Architect4r::Core::CypherMethods

Extended by:
ActiveSupport::Concern
Included in:
Server
Defined in:
lib/architect4r/core/cypher_methods.rb

Instance Method Summary collapse

Instance Method Details

#cypher_query(query, transform = true) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/architect4r/core/cypher_methods.rb', line 37

def cypher_query(query, transform=true)
  # Get data from server
  data = execute_cypher(query)
  
  Architect4r.logger.debug("[Architect4r][cypher_query] #{data.inspect}")
  
  # Create native ruby objects
  data['data'].map! do |set|
    set.map { |item| convert_if_possible(item) }
  end
  
  # Transform to hash form
  if transform
    transform_cypher_result_to_hash(data)
  else
    data
  end
end

#execute_cypher(query) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/architect4r/core/cypher_methods.rb', line 7

def execute_cypher(query)
  query = self.interpolate_node_model_root_references(query)
  
  Architect4r.logger.debug("[Architect4r][execute_cypher] QUERY: #{query}")
  
  url = prepend_base_url("/cypher")
  response = Typhoeus::Request.post(url, 
    :headers => { 'Accept' => 'application/json', 'Content-Type' => 'application/json' },
    :body => { 'query' => query }.to_json)
  
  msg = JSON.parse(response.body)
  
  Architect4r.logger.debug("[Architect4r][execute_cypher] CODE: #{response.code} => #{msg.inspect}")
  
  # Check if there might be an error with the query
  if response.code == 400
    if msg['exception'].to_s.match /org.neo4j.graphdb.NotFoundException/
      nil
    else
      raise Architect4r::InvalidCypherQuery.new(query)
    end
  elsif response.code == 500
    raise Architect4r::InvalidCypherQuery.new(query)
  elsif response.code == 204
    nil
  else
    msg
  end
end

#interpolate_node_model_root_references(query) ⇒ Object

Parses a cypher query and replaces all placeholders for model roots with the neo4j ids. It should make development faster, as you can skip manual id retrieval:

So instead of writing:

"start s=node(#{Person.model_root.id}) match s-->d return d"

you can write:

"start s=node(:person_root) match s-->d return d"


89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/architect4r/core/cypher_methods.rb', line 89

def interpolate_node_model_root_references(query)
  query.scan(/node\((:[^)]*_root)\)/i).flatten.uniq.each do |str|
    model_name = str.match(/^:(.*)_root$/)[1].to_s.classify
    if model_name.length > 0
      # As const_defined? and const_get to not support namespaces, we have to use eval :(
      begin
        query.gsub!(str, eval("#{model_name}.model_root.id.to_s"))
      rescue NoMethodError => ex
        nil
      end
    end
  end
  query
end

#transform_cypher_result_to_hash(input) ⇒ Object

Convert the columnized result array to a hashes within an array

The input would look like:

{ ‘data’ => [[‘r1’, ‘n1’], [‘r2’, ‘n2’], …], ‘columns’ => [‘rel’, ‘node’]}

And it would be transformed to:

{ ‘rel’ => ‘r1’, ‘node’ => ‘n1’ }, { ‘rel’ => ‘r2’, ‘node’ => ‘n2’ }


65
66
67
68
69
70
71
72
73
74
75
# File 'lib/architect4r/core/cypher_methods.rb', line 65

def transform_cypher_result_to_hash(input)
  results = []
  input['data'].each_with_index do |row, ri|
    result_row = {}
    input['columns'].each_with_index do |column, ci|
      result_row[column] = row[ci]
    end
    results << result_row
  end
  results
end