Class: ActiveCypher::ConnectionAdapters::MemgraphAdapter

Inherits:
AbstractBoltAdapter show all
Defined in:
lib/active_cypher/connection_adapters/memgraph_adapter.rb

Defined Under Namespace

Modules: Persistence Classes: ProtocolHandler

Constant Summary collapse

ID_FUNCTION =

Use id() for Memgraph instead of elementId()

'id'

Instance Attribute Summary

Attributes inherited from AbstractBoltAdapter

#connection

Attributes inherited from AbstractAdapter

#config

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AbstractBoltAdapter

#active?, #connect, #create_protocol_handler, #disconnect, #raw_connection, #reset!

Methods included from Instrumentation

#instrument, #instrument_connection, #instrument_query, #instrument_transaction, #sanitize_config, #sanitize_params, #sensitive_key?

Methods inherited from AbstractAdapter

#active?, #begin_transaction, #commit_transaction, #connect, #disconnect, #initialize, #inspect, #process_records, #reconnect, #rollback_transaction

Constructor Details

This class inherits a constructor from ActiveCypher::ConnectionAdapters::AbstractAdapter

Class Method Details

.id_functionObject



57
58
59
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 57

def self.id_function
  'id'
end

.node_id_equals_value(alias_name, value) ⇒ Object



49
50
51
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 49

def self.node_id_equals_value(alias_name, value)
  "id(#{alias_name}) = #{value}"
end

.node_id_where(alias_name, param_name = nil) ⇒ Object

Additional helper methods for nodes



41
42
43
44
45
46
47
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 41

def self.node_id_where(alias_name, param_name = nil)
  if param_name
    "id(#{alias_name}) = $#{param_name}"
  else
    "id(#{alias_name})"
  end
end

.return_idObject



36
37
38
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 36

def self.return_id
  'id(r) AS rid'
end

.return_node_id(alias_name, as_name = 'internal_id') ⇒ Object



53
54
55
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 53

def self.return_node_id(alias_name, as_name = 'internal_id')
  "id(#{alias_name}) AS #{as_name}"
end

.with_direct_id(id) ⇒ Object

Helper methods for Cypher query generation with IDs



20
21
22
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 20

def self.with_direct_id(id)
  "id(r) = #{id}"
end

.with_direct_node_ids(a_id, b_id) ⇒ Object



28
29
30
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 28

def self.with_direct_node_ids(a_id, b_id)
  "id(p) = #{a_id} AND id(h) = #{b_id}"
end

.with_param_idObject



24
25
26
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 24

def self.with_param_id
  'id(r) = $id'
end

.with_param_node_idsObject



32
33
34
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 32

def self.with_param_node_ids
  'id(p) = $from_id AND id(h) = $to_id'
end

Instance Method Details

#convert_access_mode(mode) ⇒ Object

Implement database-specific methods for Memgraph



97
98
99
100
101
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 97

def convert_access_mode(mode)
  # Memgraph doesn't distinguish between read/write modes
  # but we'll keep the conversion here for consistency
  mode.to_s
end

#execute_cypher(cypher, params = {}, ctx = 'Query') ⇒ Object

Memgraph defaults to **implicit auto‑commit** transactions so we simply run the Cypher and return the rows.



87
88
89
90
91
92
93
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 87

def execute_cypher(cypher, params = {}, ctx = 'Query')
  # Replace adapter-aware placeholder with Memgraph's id function
  # Because Memgraph insists on being different and using id() instead of elementId()
  cypher = cypher.gsub('__NODE_ID__', 'id')
  rows = run(cypher, params, context: ctx)
  process_records(rows)
end

#hydrate_record(record, node_alias) ⇒ Hash

Hydrates attributes from a Memgraph record

Parameters:

  • record (Hash)

    The raw record from Memgraph

  • node_alias (Symbol)

    The alias used for the node in the query

Returns:

  • (Hash)

    The hydrated attributes



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 113

def hydrate_record(record, node_alias)
  attrs = {}
  node_data = record[node_alias] || record[node_alias.to_s]

  if node_data.is_a?(Array) && node_data.length >= 2
    properties_container = node_data[1]
    if properties_container.is_a?(Array) && properties_container.length >= 3
      properties = properties_container[2]
      properties.each { |k, v| attrs[k.to_sym] = v } if properties.is_a?(Hash)
    end
  elsif node_data.is_a?(Hash)
    node_data.each { |k, v| attrs[k.to_sym] = v }
  elsif node_data.respond_to?(:properties)
    attrs = node_data.properties.symbolize_keys
  end

  attrs[:internal_id] = record[:internal_id] || record['internal_id']
  attrs
end

#id_handlerObject

Return self as id_handler for compatibility with tests



62
63
64
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 62

def id_handler
  self.class
end

#prepare_tx_metadata(metadata, _db, _access_mode) ⇒ Object



103
104
105
106
107
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 103

def (, _db, _access_mode)
  # Memgraph doesn't use db or access_mode in metadata
  # but we'll ensure metadata is returned with compact
  .compact
end

#run(cypher, params = {}, context: 'Query', db: nil, access_mode: :write) ⇒ Object

Override run to execute queries without explicit transactions Memgraph auto‑commits each query, so we send RUN + PULL directly



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 68

def run(cypher, params = {}, context: 'Query', db: nil, access_mode: :write)
  connect
  logger.debug { "[#{context}] #{cypher} #{params.inspect}" }

  instrument_query(cypher, params, context: context, metadata: { db: db, access_mode: access_mode }) do
    session = Bolt::Session.new(connection)

    rows = session.run_transaction(access_mode, db: db) do |tx|
      result = tx.run(cypher, prepare_params(params))
      result.respond_to?(:to_a) ? result.to_a : result
    end

    session.close
    rows
  end
end

#schema_catalogObject



11
12
13
14
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 11

def schema_catalog
  rows = run('SHOW SCHEMA')
  parse_schema(rows)
end

#vendorObject



9
# File 'lib/active_cypher/connection_adapters/memgraph_adapter.rb', line 9

def vendor = :memgraph