activecypher 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 614049312045dc138ca5e6aa6950333aa16936ed7f271c0dde0939971b8a4d9d
4
- data.tar.gz: 5fd731b9d85a3b45ceb5a27fb08b86904fd4adebe95aeb928cff7da3a4f556b5
3
+ metadata.gz: bfba386d94660c96cf6078ac0a7d370d2dd5670e9316a3de2ee917f409f227ab
4
+ data.tar.gz: e2e70d29dc99279b51f810363d50749e470556481e80c8c8276fc80ba612b7d4
5
5
  SHA512:
6
- metadata.gz: df907144cb86d4ba2bc10e135a71e38979a91faeaa01b1ed231841626c499f19564dbaf327df5445d7338dd7849b09196fafd42155a20e8abe51397d839c3720
7
- data.tar.gz: c4879e2edc165ea074510a759878ae99a95d12e6f74b7d4f21a0846bfcf6eedbbfe08c9ba213211ca748dbcde3e7fc2f4d8720857452376edba5c225a90e32c9
6
+ metadata.gz: 1fbe83583d2cdb4a7ea898e8ce5876cfd6907af332ffd7b77643473026ac5fd0d3714bcf037876d2c8ebd8722594a9e5635ae0b3c816c4a98ed9f49dad99e523
7
+ data.tar.gz: bc13b5392ce91d0247bd4166310e8967676763b9d11f3156206f7a8e3b004f3158b5341dfbadfec82677fc887ef6aedfc8fe51081ea722d847cce60eb155f1d0
@@ -88,10 +88,18 @@ module ActiveCypher
88
88
  run_response = connection.read_message
89
89
  unless run_response.is_a?(Bolt::Messaging::Success)
90
90
  # Read any remaining messages to clear connection state
91
- connection.read_message rescue nil
91
+ begin
92
+ connection.read_message
93
+ rescue StandardError
94
+ nil
95
+ end
92
96
  # Send RESET to clear connection state
93
97
  connection.write_message(Bolt::Messaging::Reset.new)
94
- connection.read_message rescue nil
98
+ begin
99
+ connection.read_message
100
+ rescue StandardError
101
+ nil
102
+ end
95
103
  raise QueryError, "DDL failed for: #{cypher.inspect}\nError: #{run_response.fields.first}"
96
104
  end
97
105
 
@@ -100,22 +108,71 @@ module ActiveCypher
100
108
  end
101
109
  end
102
110
 
103
- # Override run to execute queries without explicit transactions
104
- # Memgraph autocommits each query, so we send RUN + PULL directly
111
+ # Override run to execute queries using auto-commit mode.
112
+ # Memgraph auto-commits each query, so we send RUN + PULL directly
113
+ # without BEGIN/COMMIT wrapper. This avoids transaction state issues.
105
114
  def run(cypher, params = {}, context: 'Query', db: nil, access_mode: :write)
106
115
  connect
107
116
  logger.debug { "[#{context}] #{cypher} #{params.inspect}" }
108
117
 
109
118
  instrument_query(cypher, params, context: context, metadata: { db: db, access_mode: access_mode }) do
110
- session = Bolt::Session.new(connection)
119
+ run_auto_commit(cypher, prepare_params(params))
120
+ end
121
+ end
111
122
 
112
- rows = session.run_transaction(access_mode, db: db) do |tx|
113
- result = tx.run(cypher, prepare_params(params))
114
- result.respond_to?(:to_a) ? result.to_a : result
115
- end
123
+ # Execute a query in auto-commit mode (no explicit transaction).
124
+ # Sends RUN + PULL directly to the connection.
125
+ #
126
+ # @param cypher [String] The Cypher query
127
+ # @param params [Hash] Query parameters
128
+ # @return [Array<Hash>] The result rows
129
+ def run_auto_commit(cypher, params = {})
130
+ Sync do
131
+ # Send RUN message
132
+ run_meta = {}
133
+ connection.write_message(Bolt::Messaging::Run.new(cypher, params, run_meta))
116
134
 
117
- session.close
118
- rows
135
+ # Read RUN response
136
+ run_response = connection.read_message
137
+
138
+ case run_response
139
+ when Bolt::Messaging::Success
140
+ # Send PULL to get results
141
+ connection.write_message(Bolt::Messaging::Pull.new({ n: -1 }))
142
+
143
+ # Collect records
144
+ rows = []
145
+ fields = run_response.metadata['fields'] || []
146
+
147
+ loop do
148
+ msg = connection.read_message
149
+ case msg
150
+ when Bolt::Messaging::Record
151
+ # Convert record values to hash with field names
152
+ row = fields.zip(msg.values).to_h
153
+ rows << row
154
+ when Bolt::Messaging::Success
155
+ # End of results
156
+ break
157
+ when Bolt::Messaging::Failure
158
+ code = msg.metadata['code']
159
+ message = msg.metadata['message']
160
+ connection.reset!
161
+ raise QueryError, "Query failed: #{code} - #{message}"
162
+ else
163
+ raise ProtocolError, "Unexpected response during PULL: #{msg.class}"
164
+ end
165
+ end
166
+
167
+ rows
168
+ when Bolt::Messaging::Failure
169
+ code = run_response.metadata['code']
170
+ message = run_response.metadata['message']
171
+ connection.reset!
172
+ raise QueryError, "Query failed: #{code} - #{message}"
173
+ else
174
+ raise ProtocolError, "Unexpected response to RUN: #{run_response.class}"
175
+ end
119
176
  end
120
177
  end
121
178
 
@@ -59,26 +59,26 @@ module ActiveCypher
59
59
  # --------------------------------------------------------------
60
60
  # Connection fallback
61
61
  # --------------------------------------------------------------
62
- # Relationship classes usually share the same Bolt pool as the
63
- # node they originate from; delegate there unless the relationship
64
- # class was given its own pool explicitly.
65
- #
66
- # WorksAtRelationship.connection # -> PersonNode.connection
67
- #
68
- def self.connection
69
- # If this is a concrete relationship class with from_class defined,
70
- # prefer delegating to that node's connection (so role/shard routing is respected).
71
- if !abstract_class? && (fc = from_class_name)
72
- klass = fc.constantize
73
- role = ActiveCypher::RuntimeRegistry.current_role
74
- shard = ActiveCypher::RuntimeRegistry.current_shard
75
-
76
- return klass.connected_to(role: role, shard: shard) do
77
- klass.connection
78
- end
62
+ # Relationship classes usually share the same Bolt pool as the
63
+ # node they originate from; delegate there unless the relationship
64
+ # class was given its own pool explicitly.
65
+ #
66
+ # WorksAtRelationship.connection # -> PersonNode.connection
67
+ #
68
+ def self.connection
69
+ # If this is a concrete relationship class with from_class defined,
70
+ # prefer delegating to that node's connection (so role/shard routing is respected).
71
+ if !abstract_class? && (fc = from_class_name)
72
+ klass = fc.constantize
73
+ role = ActiveCypher::RuntimeRegistry.current_role
74
+ shard = ActiveCypher::RuntimeRegistry.current_shard
75
+
76
+ return klass.connected_to(role: role, shard: shard) do
77
+ klass.connection
79
78
  end
79
+ end
80
80
 
81
- # Otherwise, fall back to node_base_class if present (even if abstract)
81
+ # Otherwise, fall back to node_base_class if present (even if abstract)
82
82
  if (klass = node_base_class)
83
83
  return klass.connection
84
84
  end
@@ -313,12 +313,10 @@ module ActiveCypher
313
313
  end
314
314
  rescue ActiveCypher::RecordNotSaved, RuntimeError => e
315
315
  # Only catch specific validation errors, let other errors propagate
316
- if e.message.include?('must be persisted') || e.message.include?('creation returned no id')
317
- log_error "Failed to save #{self.class}: #{e.message}"
318
- false
319
- else
320
- raise
321
- end
316
+ raise unless e.message.include?('must be persisted') || e.message.include?('creation returned no id')
317
+
318
+ log_error "Failed to save #{self.class}: #{e.message}"
319
+ false
322
320
  end
323
321
 
324
322
  # Bang version of save - raises exception if save fails
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveCypher
4
- VERSION = '0.14.0'
4
+ VERSION = '0.14.1'
5
5
 
6
6
  def self.gem_version
7
7
  Gem::Version.new VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activecypher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih