Class: Neo4j::Server::CypherSession

Inherits:
Neo4j::Session show all
Includes:
Resource
Defined in:
lib/neo4j-server/cypher_session.rb

Constant Summary collapse

DEFAULT_RETRY_COUNT =
ENV['NEO4J_RETRY_COUNT'].nil? ? 10 : ENV['NEO4J_RETRY_COUNT'].to_i
EMPTY =
''
NEWLINE_W_SPACES =
"\n  "

Instance Attribute Summary collapse

Attributes included from Resource

#resource_data, #resource_url

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Resource

#convert_from_json_value, #expect_response_code!, #handle_response_error!, #init_resource_data, #resource_headers, #resource_url_id, #response_exception, #wrap_resource

Methods inherited from Neo4j::Session

_listeners, _notify_listeners, add_listener, #auto_commit?, clear_listeners, #close, create_session, current, current!, inspect, named, on_next_session_available, query, register, register_db, #running, set_current, #shutdown, #start, #transaction_class, unregister, user_agent_string, validate_session_num!

Constructor Details

#initialize(data_url, connection) ⇒ CypherSession

Returns a new instance of CypherSession.



15
16
17
18
19
20
# File 'lib/neo4j-server/cypher_session.rb', line 15

def initialize(data_url, connection)
  @connection = connection
  Neo4j::Session.register(self)
  initialize_resource(data_url)
  Neo4j::Session._notify_listeners(:session_available, self)
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



13
14
15
# File 'lib/neo4j-server/cypher_session.rb', line 13

def connection
  @connection
end

Class Method Details

.create_connection(params, url = nil) ⇒ Faraday

Parameters:

  • params (Hash)

    could be empty or contain basic authentication user and password

Returns:

  • (Faraday)

See Also:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/neo4j-server/cypher_session.rb', line 25

def self.create_connection(params, url = nil)
  init_params = params[:initialize] && params.delete(:initialize)
  conn = Faraday.new(url, init_params) do |b|
    b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
    b.request :multi_json
    # b.response :logger, ::Logger.new(STDOUT), bodies: true

    b.response :multi_json, symbolize_keys: true, content_type: 'application/json'
    # b.use Faraday::Response::RaiseError
    require 'typhoeus'
    require 'typhoeus/adapters/faraday'
    b.adapter :typhoeus
    # b.adapter  Faraday.default_adapter
  end
  conn.headers = {'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string}
  conn
end

.establish_session(root_data, connection) ⇒ Object



57
58
59
60
61
# File 'lib/neo4j-server/cypher_session.rb', line 57

def self.establish_session(root_data, connection)
  data_url = root_data[:data]
  data_url << '/' unless data_url.nil? || data_url.end_with?('/')
  CypherSession.new(data_url, connection)
end

.log_withObject



252
253
254
255
256
257
258
259
260
# File 'lib/neo4j-server/cypher_session.rb', line 252

def self.log_with
  ActiveSupport::Notifications.subscribe('neo4j.cypher_query') do |_, start, finish, _id, payload|
    ms = (finish - start) * 1000
    params_string = (payload[:params] && !payload[:params].empty? ? "| #{payload[:params].inspect}" : EMPTY)
    cypher = payload[:pretty_cypher] ? NEWLINE_W_SPACES + payload[:pretty_cypher].gsub(/\n/, NEWLINE_W_SPACES) : payload[:cypher]

    yield(" #{ANSI::CYAN}#{payload[:context] || 'CYPHER'}#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{cypher} #{params_string}")
  end
end

.open(endpoint_url = nil, params = {}) ⇒ Object

Opens a session to the database

Parameters:

  • endpoint_url (String) (defaults to: nil)
  • params (Hash) (defaults to: {})

    faraday params, see #create_connection or an already created faraday connection

See Also:

  • Neo4j::Session#open


48
49
50
51
52
53
54
55
# File 'lib/neo4j-server/cypher_session.rb', line 48

def self.open(endpoint_url = nil, params = {})
  extract_basic_auth(endpoint_url, params)
  url = endpoint_url || 'http://localhost:7474'
  connection = params[:connection] || create_connection(params, url)
  response = connection.get(url)
  fail "Server not available on #{url} (response code #{response.status})" unless response.status == 200
  establish_session(response.body, connection)
end

.transaction_classObject



95
96
97
# File 'lib/neo4j-server/cypher_session.rb', line 95

def self.transaction_class
  Neo4j::Server::CypherTransaction
end

Instance Method Details

#_query(query, params = {}, options = {}) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/neo4j-server/cypher_session.rb', line 215

def _query(query, params = {}, options = {})
  query, params = query_and_params(query, params)

  ActiveSupport::Notifications.instrument('neo4j.cypher_query', params: params, context: options[:context],
                                                                cypher: query, pretty_cypher: options[:pretty_cypher]) do
    if current_transaction
      current_transaction._query(query, params)
    else
      query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
      response = @connection.post(resource_url(:cypher), query)
      CypherResponse.create_with_no_tx(response)
    end
  end
end

#_query_data(query) ⇒ Object



179
180
181
182
# File 'lib/neo4j-server/cypher_session.rb', line 179

def _query_data(query)
  r = _query_or_fail(query, true)
  Neo4j::Transaction.current ? r : r[:data]
end

#_query_entity_data(query, id = nil, params = {}) ⇒ Object



211
212
213
# File 'lib/neo4j-server/cypher_session.rb', line 211

def _query_entity_data(query, id = nil, params = {})
  _query(query, params).tap(&:raise_if_cypher_error!).entity_data(id)
end

#_query_or_fail(query, single_row = false, params = {}, retry_count = DEFAULT_RETRY_COUNT) ⇒ Object



186
187
188
189
190
191
192
193
194
195
# File 'lib/neo4j-server/cypher_session.rb', line 186

def _query_or_fail(query, single_row = false, params = {}, retry_count = DEFAULT_RETRY_COUNT)
  query, params = query_and_params(query, params)

  response = _query(query, params)
  if response.error?
    _retry_or_raise(query, params, single_row, retry_count, response)
  else
    single_row ? response.first_data : response
  end
end

#_retry_or_raise(query, params, single_row, retry_count, response) ⇒ Object



206
207
208
209
# File 'lib/neo4j-server/cypher_session.rb', line 206

def _retry_or_raise(query, params, single_row, retry_count, response)
  response.raise_error unless response.retryable_error?
  retry_count > 0 ? _query_or_fail(query, single_row, params, retry_count - 1) : response.raise_error
end

#create_label(name) ⇒ Object



139
140
141
# File 'lib/neo4j-server/cypher_session.rb', line 139

def create_label(name)
  CypherLabel.new(self, name)
end

#create_node(props = nil, labels = []) ⇒ Object



116
117
118
119
120
121
122
123
124
125
# File 'lib/neo4j-server/cypher_session.rb', line 116

def create_node(props = nil, labels = [])
  label_string = labels.empty? ? '' : (':' + labels.map { |k| "`#{k}`" }.join(':'))
  if !props.nil?
    prop = '{props}'
    props.each_key { |k| props.delete(k) if props[k].nil? }
  end

  id = _query_or_fail("CREATE (n#{label_string} #{prop}) RETURN ID(n)", true, props: props)
  CypherNode.new(self, props.nil? ? id : {id: id, metadata: {labels: labels}, data: props})
end

#current_transactionObject



246
247
248
# File 'lib/neo4j-server/cypher_session.rb', line 246

def current_transaction
  Neo4j::Transaction.current_for(self)
end

#db_typeObject



70
71
72
# File 'lib/neo4j-server/cypher_session.rb', line 70

def db_type
  :server_db
end

#find_all_nodes(label_name) ⇒ Object



157
158
159
# File 'lib/neo4j-server/cypher_session.rb', line 157

def find_all_nodes(label_name)
  search_result_to_enumerable_first_column(_query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)"))
end

#find_nodes(label_name, key, value) ⇒ Object



161
162
163
164
165
166
# File 'lib/neo4j-server/cypher_session.rb', line 161

def find_nodes(label_name, key, value)
  value = "'#{value}'" if value.is_a? String

  response = _query_or_fail("MATCH (n:`#{label_name}`) WHERE n.#{key} = #{value} RETURN ID(n)")
  search_result_to_enumerable_first_column(response)
end

#indexes(label) ⇒ Object



147
148
149
# File 'lib/neo4j-server/cypher_session.rb', line 147

def indexes(label)
  schema_properties("/db/data/schema/index/#{label}")
end

#initialize_resource(data_url) ⇒ Object



86
87
88
89
90
91
92
93
# File 'lib/neo4j-server/cypher_session.rb', line 86

def initialize_resource(data_url)
  response = @connection.get(data_url)
  expect_response_code!(response, 200)
  data_resource = response.body
  fail "No data_resource for #{response.body}" unless data_resource
  # store the resource data
  init_resource_data(data_resource, data_url)
end

#inspectObject



78
79
80
# File 'lib/neo4j-server/cypher_session.rb', line 78

def inspect
  "#{self} version: '#{version}'"
end

#load_node(neo_id) ⇒ Object



127
128
129
# File 'lib/neo4j-server/cypher_session.rb', line 127

def load_node(neo_id)
  query.unwrapped.match(:n).where(n: {neo_id: neo_id}).pluck(:n).first
end

#load_relationship(neo_id) ⇒ Object



131
132
133
134
135
136
137
# File 'lib/neo4j-server/cypher_session.rb', line 131

def load_relationship(neo_id)
  query.unwrapped.optional_match('(n)-[r]-()').where(r: {neo_id: neo_id}).pluck(:r).first
rescue Neo4j::Session::CypherError => cypher_error
  return nil if cypher_error.message =~ /not found$/

  raise cypher_error
end

#query(*args) ⇒ Object



168
169
170
171
172
173
174
175
176
177
# File 'lib/neo4j-server/cypher_session.rb', line 168

def query(*args)
  if [[String], [String, Hash]].include?(args.map(&:class))
    response = _query(*args)
    response.raise_error if response.error?
    response.to_node_enumeration(args[0])
  else
    options = args[0] || {}
    Neo4j::Core::Query.new(options.merge(session: self))
  end
end

#query_and_params(query_or_query_string, params) ⇒ Object



197
198
199
200
201
202
203
204
# File 'lib/neo4j-server/cypher_session.rb', line 197

def query_and_params(query_or_query_string, params)
  if query_or_query_string.is_a?(::Neo4j::Core::Query)
    cypher = query_or_query_string.to_cypher
    [cypher, query_or_query_string.send(:merge_params).merge(params)]
  else
    [query_or_query_string, params]
  end
end

#schema_properties(query_string) ⇒ Object



151
152
153
154
155
# File 'lib/neo4j-server/cypher_session.rb', line 151

def schema_properties(query_string)
  response = @connection.get(query_string)
  expect_response_code!(response, 200)
  {property_keys: response.body.map! { |row| row[:property_keys].map(&:to_sym) }}
end

#search_result_to_enumerable_first_column(response) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/neo4j-server/cypher_session.rb', line 230

def search_result_to_enumerable_first_column(response)
  return [] unless response.data

  Enumerator.new do |yielder|
    response.data.each do |data|
      if current_transaction
        data[:row].each do |id|
          yielder << CypherNode.new(self, id).wrapper
        end
      else
        yielder << CypherNode.new(self, data[0]).wrapper
      end
    end
  end
end

#super_queryObject



12
# File 'lib/neo4j-server/cypher_session.rb', line 12

alias super_query query

#to_sObject



74
75
76
# File 'lib/neo4j-server/cypher_session.rb', line 74

def to_s
  "#{self.class} url: '#{@resource_url}'"
end

#transactionObject

Duplicate of CypherSession::Adaptor::Base#transaction



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/neo4j-server/cypher_session.rb', line 100

def transaction
  return self.class.transaction_class.new(self) if !block_given?

  begin
    tx = transaction

    yield tx
  rescue Exception => e # rubocop:disable Lint/RescueException
    tx.mark_failed

    raise e
  ensure
    tx.close
  end
end

#uniqueness_constraints(label) ⇒ Object



143
144
145
# File 'lib/neo4j-server/cypher_session.rb', line 143

def uniqueness_constraints(label)
  schema_properties("/db/data/schema/constraint/#{label}/uniqueness")
end

#versionObject



82
83
84
# File 'lib/neo4j-server/cypher_session.rb', line 82

def version
  resource_data ? resource_data[:neo4j_version] : ''
end