neo4j-core 6.1.6 → 7.0.0.alpha.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -9
  3. data/README.md +48 -0
  4. data/lib/neo4j-core.rb +23 -0
  5. data/lib/neo4j-core/helpers.rb +8 -0
  6. data/lib/neo4j-core/query.rb +23 -20
  7. data/lib/neo4j-core/query_clauses.rb +18 -32
  8. data/lib/neo4j-core/query_find_in_batches.rb +3 -1
  9. data/lib/neo4j-core/version.rb +1 -1
  10. data/lib/neo4j-embedded/cypher_response.rb +4 -0
  11. data/lib/neo4j-embedded/embedded_database.rb +3 -5
  12. data/lib/neo4j-embedded/embedded_node.rb +4 -4
  13. data/lib/neo4j-embedded/embedded_session.rb +21 -10
  14. data/lib/neo4j-embedded/embedded_transaction.rb +4 -10
  15. data/lib/neo4j-server/cypher_node.rb +5 -4
  16. data/lib/neo4j-server/cypher_relationship.rb +3 -3
  17. data/lib/neo4j-server/cypher_response.rb +4 -0
  18. data/lib/neo4j-server/cypher_session.rb +31 -22
  19. data/lib/neo4j-server/cypher_transaction.rb +23 -15
  20. data/lib/neo4j-server/resource.rb +3 -4
  21. data/lib/neo4j/core/cypher_session.rb +17 -9
  22. data/lib/neo4j/core/cypher_session/adaptors.rb +116 -33
  23. data/lib/neo4j/core/cypher_session/adaptors/bolt.rb +331 -0
  24. data/lib/neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io.rb +76 -0
  25. data/lib/neo4j/core/cypher_session/adaptors/bolt/pack_stream.rb +288 -0
  26. data/lib/neo4j/core/cypher_session/adaptors/embedded.rb +60 -29
  27. data/lib/neo4j/core/cypher_session/adaptors/has_uri.rb +63 -0
  28. data/lib/neo4j/core/cypher_session/adaptors/http.rb +123 -119
  29. data/lib/neo4j/core/cypher_session/responses.rb +17 -2
  30. data/lib/neo4j/core/cypher_session/responses/bolt.rb +135 -0
  31. data/lib/neo4j/core/cypher_session/responses/embedded.rb +46 -11
  32. data/lib/neo4j/core/cypher_session/responses/http.rb +49 -40
  33. data/lib/neo4j/core/cypher_session/transactions.rb +33 -0
  34. data/lib/neo4j/core/cypher_session/transactions/bolt.rb +36 -0
  35. data/lib/neo4j/core/cypher_session/transactions/embedded.rb +32 -0
  36. data/lib/neo4j/core/cypher_session/transactions/http.rb +52 -0
  37. data/lib/neo4j/core/instrumentable.rb +2 -2
  38. data/lib/neo4j/core/label.rb +182 -0
  39. data/lib/neo4j/core/node.rb +8 -3
  40. data/lib/neo4j/core/relationship.rb +12 -4
  41. data/lib/neo4j/entity_equality.rb +1 -1
  42. data/lib/neo4j/session.rb +4 -5
  43. data/lib/neo4j/transaction.rb +108 -72
  44. data/neo4j-core.gemspec +6 -6
  45. metadata +34 -40
@@ -1,12 +1,11 @@
1
1
  module Neo4j
2
2
  module Embedded
3
- class EmbeddedTransaction
3
+ class EmbeddedTransaction < Neo4j::Transaction::Base
4
4
  attr_reader :root_tx
5
- include Neo4j::Transaction::Instance
6
5
 
7
- def initialize(root_tx)
8
- @root_tx = root_tx
9
- register_instance
6
+ def initialize(session)
7
+ super
8
+ @root_tx = @session.begin_tx
10
9
  end
11
10
 
12
11
  def acquire_read_lock(entity)
@@ -17,11 +16,6 @@ module Neo4j
17
16
  @root_tx.acquire_write_lock(entity)
18
17
  end
19
18
 
20
-
21
- def inspect
22
- "EmbeddedTransaction [nested: #{@pushed_nested} failed?: #{failure?} active: #{Neo4j::Transaction.current == self}]"
23
- end
24
-
25
19
  def delete
26
20
  @root_tx.failure
27
21
  @root_tx.close
@@ -32,7 +32,7 @@ module Neo4j
32
32
  # (see Neo4j::Node#create_rel)
33
33
  def create_rel(type, other_node, props = nil)
34
34
  q = @session.query.match(:a, :b).where(a: {neo_id: neo_id}, b: {neo_id: other_node.neo_id})
35
- .create("(a)-[r:`#{type}`]->(b)").break.set(r: props).return(r: :neo_id)
35
+ .create("(a)-[r:`#{type}`]->(b)").break.set(r: props).return(r: :neo_id)
36
36
 
37
37
  id = @session._query_or_fail(q, true)
38
38
 
@@ -138,8 +138,8 @@ module Neo4j
138
138
  @session._query_or_fail(query, false)
139
139
  end
140
140
 
141
- alias_method :delete, :del
142
- alias_method :destroy, :del
141
+ alias delete del
142
+ alias destroy del
143
143
 
144
144
  # (see Neo4j::Node#exist?)
145
145
  def exist?
@@ -193,10 +193,11 @@ module Neo4j
193
193
 
194
194
  private
195
195
 
196
+ DEFAULT_RELATIONSHIP_ARROW_DIRECTION = :both
196
197
  def relationship_arrow(match)
197
198
  rel_spec = match[:type] ? "[r:`#{match[:type]}`]" : '[r]'
198
199
 
199
- case match[:dir] || :both
200
+ case match[:dir] || DEFAULT_RELATIONSHIP_ARROW_DIRECTION
200
201
  when :outgoing then "-#{rel_spec}->"
201
202
  when :incoming then "<-#{rel_spec}-"
202
203
  when :both then "-#{rel_spec}-"
@@ -19,7 +19,7 @@ module Neo4j
19
19
  def ==(other)
20
20
  other.class == self.class && other.neo_id == neo_id
21
21
  end
22
- alias_method :eql?, :==
22
+ alias eql? ==
23
23
 
24
24
  attr_reader :id
25
25
 
@@ -115,8 +115,8 @@ module Neo4j
115
115
  def del
116
116
  @session._query("#{match_start} DELETE n", neo_id: neo_id)
117
117
  end
118
- alias_method :delete, :del
119
- alias_method :destroy, :del
118
+ alias delete del
119
+ alias destroy del
120
120
 
121
121
  def exist?
122
122
  response = @session._query("#{match_start} RETURN n", neo_id: neo_id)
@@ -155,6 +155,10 @@ module Neo4j
155
155
  !!@error
156
156
  end
157
157
 
158
+ def raise_if_cypher_error!
159
+ raise_cypher_error if error?
160
+ end
161
+
158
162
  RETRYABLE_ERROR_STATUSES = %w(DeadlockDetectedException AcquireLockTimeoutException ExternalResourceFailureException UnknownFailureException)
159
163
  def retryable_error?
160
164
  return unless error?
@@ -9,7 +9,7 @@ module Neo4j
9
9
  class CypherSession < Neo4j::Session
10
10
  include Resource
11
11
 
12
- alias_method :super_query, :query
12
+ alias super_query query
13
13
  attr_reader :connection
14
14
 
15
15
  def initialize(data_url, connection)
@@ -27,7 +27,7 @@ module Neo4j
27
27
  conn = Faraday.new(url, init_params) do |b|
28
28
  b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
29
29
  b.request :multi_json
30
- # b.response :logger
30
+ # b.response :logger, ::Logger.new(STDOUT), bodies: true
31
31
 
32
32
  b.response :multi_json, symbolize_keys: true, content_type: 'application/json'
33
33
  # b.use Faraday::Response::RaiseError
@@ -90,14 +90,25 @@ module Neo4j
90
90
  init_resource_data(data_resource, data_url)
91
91
  end
92
92
 
93
- def close
94
- super
95
- Neo4j::Transaction.unregister_current
93
+ def self.transaction_class
94
+ Neo4j::Server::CypherTransaction
96
95
  end
97
96
 
98
- def begin_tx
99
- Neo4j::Transaction.current ? Neo4j::Transaction.current.push_nested! : wrap_resource(@connection)
100
- Neo4j::Transaction.current
97
+ # Duplicate of CypherSession::Adaptor::Base#transaction
98
+ def transaction
99
+ return self.class.transaction_class.new(self) if !block_given?
100
+
101
+ begin
102
+ tx = transaction
103
+
104
+ yield tx
105
+ rescue Exception => e # rubocop:disable Lint/RescueException
106
+ tx.mark_failed
107
+
108
+ raise e
109
+ ensure
110
+ tx.close
111
+ end
101
112
  end
102
113
 
103
114
  def create_node(props = nil, labels = [])
@@ -118,7 +129,7 @@ module Neo4j
118
129
  def load_relationship(neo_id)
119
130
  query.unwrapped.optional_match('(n)-[r]-()').where(r: {neo_id: neo_id}).pluck(:r).first
120
131
  rescue Neo4j::Session::CypherError => cypher_error
121
- return nil if cypher_error.message.match(/not found$/)
132
+ return nil if cypher_error.message =~ /not found$/
122
133
 
123
134
  raise cypher_error
124
135
  end
@@ -154,12 +165,9 @@ module Neo4j
154
165
 
155
166
  def query(*args)
156
167
  if [[String], [String, Hash]].include?(args.map(&:class))
157
- query = args[0]
158
- params = args[1]
159
-
160
- response = _query(query, params)
168
+ response = _query(*args)
161
169
  response.raise_error if response.error?
162
- response.to_node_enumeration(query)
170
+ response.to_node_enumeration(args[0])
163
171
  else
164
172
  options = args[0] || {}
165
173
  Neo4j::Core::Query.new(options.merge(session: self))
@@ -199,19 +207,16 @@ module Neo4j
199
207
  end
200
208
 
201
209
  def _query_entity_data(query, id = nil, params = {})
202
- _query(query, params).tap do |response|
203
- response.raise_error if response.error?
204
- end.entity_data(id)
210
+ _query(query, params).tap(&:raise_if_cypher_error!).entity_data(id)
205
211
  end
206
212
 
207
213
  def _query(query, params = {}, options = {})
208
214
  query, params = query_and_params(query, params)
209
215
 
210
- curr_tx = Neo4j::Transaction.current
211
216
  ActiveSupport::Notifications.instrument('neo4j.cypher_query', params: params, context: options[:context],
212
217
  cypher: query, pretty_cypher: options[:pretty_cypher]) do
213
- if curr_tx
214
- curr_tx._query(query, params)
218
+ if current_transaction
219
+ current_transaction._query(query, params)
215
220
  else
216
221
  query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
217
222
  response = @connection.post(resource_url(:cypher), query)
@@ -225,7 +230,7 @@ module Neo4j
225
230
 
226
231
  Enumerator.new do |yielder|
227
232
  response.data.each do |data|
228
- if Neo4j::Transaction.current
233
+ if current_transaction
229
234
  data[:row].each do |id|
230
235
  yielder << CypherNode.new(self, id).wrapper
231
236
  end
@@ -236,12 +241,16 @@ module Neo4j
236
241
  end
237
242
  end
238
243
 
244
+ def current_transaction
245
+ Neo4j::Transaction.current_for(self)
246
+ end
247
+
239
248
  EMPTY = ''
240
249
  NEWLINE_W_SPACES = "\n "
241
250
  def self.log_with
242
251
  ActiveSupport::Notifications.subscribe('neo4j.cypher_query') do |_, start, finish, _id, payload|
243
252
  ms = (finish - start) * 1000
244
- params_string = (payload[:params] && payload[:params].size > 0 ? "| #{payload[:params].inspect}" : EMPTY)
253
+ params_string = (payload[:params] && !payload[:params].empty? ? "| #{payload[:params].inspect}" : EMPTY)
245
254
  cypher = payload[:pretty_cypher] ? NEWLINE_W_SPACES + payload[:pretty_cypher].gsub(/\n/, NEWLINE_W_SPACES) : payload[:cypher]
246
255
 
247
256
  yield(" #{ANSI::CYAN}#{payload[:context] || 'CYPHER'}#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{cypher} #{params_string}")
@@ -7,16 +7,20 @@ module Neo4j
7
7
  # * `close` is called to end the transaction. It calls `commit` or `delete`.
8
8
  #
9
9
  # If a transaction is created and then closed without performing any queries, an OpenStruct is returned that behaves like a successfully closed query.
10
- class CypherTransaction
11
- include Neo4j::Transaction::Instance
10
+ class CypherTransaction < Neo4j::Transaction::Base
12
11
  include Resource
13
12
 
14
- attr_reader :commit_url, :query_url, :base_url, :connection
13
+ attr_reader :commit_url, :query_url
15
14
 
16
- def initialize(url, session_connection)
17
- @base_url = url
18
- @connection = session_connection
19
- register_instance
15
+ def connection
16
+ @session.connection
17
+ end
18
+
19
+ def base_url
20
+ require 'uri'
21
+ URI(@session.instance_variable_get('@resource_url')).tap do |uri|
22
+ uri.path = ''
23
+ end.to_s
20
24
  end
21
25
 
22
26
  ROW_REST = %w(row REST)
@@ -31,28 +35,34 @@ module Neo4j
31
35
  end
32
36
 
33
37
  def start(body)
34
- request(:post, @base_url, 201, body).tap do |response|
38
+ request(:post, start_url, 201, body).tap do |response|
35
39
  @commit_url = response.body[:commit]
36
40
  @query_url = response.headers[:Location]
37
41
 
38
42
  fail "NO ENDPOINT URL #{connection} : HEAD: #{response.headers.inspect}" if !@query_url || @query_url.empty?
39
43
 
40
- init_resource_data(response.body, @base_url)
44
+ init_resource_data(response.body, base_url)
41
45
  end
42
46
  end
43
47
 
48
+ def start_url
49
+ @session.resource_data.fetch(:transaction) || base_url
50
+ end
51
+
44
52
  def query(body)
45
53
  request(:post, @query_url, 200, body)
46
54
  end
47
55
 
56
+ EMPTY_RESPONSE = OpenStruct.new(status: 200, body: '')
57
+
48
58
  def delete
49
- return empty_response if !@commit_url || expired?
59
+ return EMPTY_RESPONSE if !@commit_url || expired?
50
60
 
51
61
  request(:delete, @query_url, 200, nil, resource_headers)
52
62
  end
53
63
 
54
64
  def commit
55
- return empty_response if !@commit_url || expired?
65
+ return EMPTY_RESPONSE if !@commit_url || expired?
56
66
 
57
67
  request(:post, @commit_url, 200, nil, resource_headers)
58
68
  end
@@ -66,11 +76,9 @@ module Neo4j
66
76
  end
67
77
 
68
78
  def create_cypher_response(response)
69
- first_result = response.body[:results][0]
70
-
71
79
  CypherResponse.new(response, true).tap do |cypher_response|
72
80
  if response.body[:errors].empty?
73
- cypher_response.set_data(first_result)
81
+ cypher_response.set_data(response.body[:results][0])
74
82
  else
75
83
  first_error = response.body[:errors].first
76
84
  tx_cleanup!(first_error)
@@ -81,7 +89,7 @@ module Neo4j
81
89
 
82
90
  def tx_cleanup!(first_error)
83
91
  autoclosed!
84
- mark_expired if first_error[:message].match(/Unrecognized transaction id/)
92
+ mark_expired if first_error[:message] =~ /Unrecognized transaction id/
85
93
  end
86
94
 
87
95
  def empty_response
@@ -16,14 +16,13 @@ module Neo4j
16
16
  self
17
17
  end
18
18
 
19
- def wrap_resource(connection = Neo4j::Session.current)
20
- url = resource_url(:transaction)
21
- CypherTransaction.new(url, connection)
19
+ def wrap_resource(connection)
20
+ CypherTransaction.new(resource_url(:transaction), connection)
22
21
  end
23
22
 
24
23
  def resource_url(key = nil)
25
24
  return @resource_url if key.nil?
26
- @resource_data.fetch key
25
+ resource_data.fetch key
27
26
  rescue KeyError
28
27
  raise "No resource key '#{key}', available #{@resource_data.keys.inspect}"
29
28
  end
@@ -1,7 +1,8 @@
1
-
2
1
  module Neo4j
3
2
  module Core
4
3
  class CypherSession
4
+ attr_reader :adaptor
5
+
5
6
  def initialize(adaptor)
6
7
  fail ArgumentError, "Invalid adaptor: #{adaptor.inspect}" if !adaptor.is_a?(Adaptors::Base)
7
8
 
@@ -10,22 +11,29 @@ module Neo4j
10
11
  @adaptor.connect
11
12
  end
12
13
 
14
+ def transaction_class
15
+ Neo4j::Core::CypherSession::Transactions::Base
16
+ end
17
+
18
+ %w(
19
+ version
20
+ ).each do |method, &_block|
21
+ define_method(method) do |*args, &block|
22
+ @adaptor.send(method, *args, &block)
23
+ end
24
+ end
25
+
13
26
  %w(
14
27
  query
15
28
  queries
16
29
 
17
- start_transaction
18
- end_transaction
19
30
  transaction
20
- transaction_started?
21
31
 
22
- version
23
-
24
- indexes_for_label
25
- uniqueness_constraints_for_label
32
+ indexes
33
+ constraints
26
34
  ).each do |method, &_block|
27
35
  define_method(method) do |*args, &block|
28
- @adaptor.send(method, *args, &block)
36
+ @adaptor.send(method, self, *args, &block)
29
37
  end
30
38
  end
31
39
  end
@@ -1,19 +1,61 @@
1
1
  require 'neo4j/core/cypher_session'
2
2
  require 'neo4j/core/instrumentable'
3
+ require 'neo4j/core/label'
3
4
 
4
5
  module Neo4j
5
6
  module Core
6
7
  class CypherSession
8
+ class CypherError < StandardError
9
+ attr_reader :code, :message, :stack_trace
10
+
11
+ def self.new_from(code, message, stack_trace = nil)
12
+ @code = code
13
+ @message = message
14
+ @stack_trace = stack_trace
15
+
16
+ msg = <<-ERROR
17
+ Cypher error:
18
+ #{ANSI::CYAN}#{code}#{ANSI::CLEAR}: #{message}
19
+ #{stack_trace}
20
+ ERROR
21
+
22
+ error_class_from(code).new(msg)
23
+ end
24
+
25
+ def self.error_class_from(code)
26
+ case code
27
+ when /(ConstraintValidationFailed|ConstraintViolation)/
28
+ SchemaErrors::ConstraintValidationFailedError
29
+ else
30
+ CypherError
31
+ end
32
+ end
33
+ end
34
+ module SchemaErrors
35
+ class ConstraintValidationFailedError < CypherError; end
36
+ end
37
+
7
38
  module Adaptors
8
39
  MAP = {}
9
40
 
10
41
  class Base
11
42
  include Neo4j::Core::Instrumentable
12
43
 
44
+ gem, version = if defined?(::Neo4j::ActiveNode)
45
+ ['neo4j', ::Neo4j::VERSION]
46
+ else
47
+ ['neo4j-core', ::Neo4j::Core::VERSION]
48
+ end
49
+
50
+
51
+ USER_AGENT_STRING = "#{gem}-gem/#{version} (https://github.com/neo4jrb/#{gem})"
52
+
13
53
  def connect(*_args)
14
54
  fail '#connect not implemented!'
15
55
  end
16
56
 
57
+ attr_accessor :wrap_level
58
+
17
59
  Query = Struct.new(:cypher, :parameters, :pretty_cypher, :context)
18
60
 
19
61
  class QueryBuilder
@@ -43,57 +85,71 @@ module Neo4j
43
85
  end
44
86
  end
45
87
 
46
- def query(*args)
47
- queries { append(*args) }[0]
88
+ def query(session, *args)
89
+ options = (args.size == 3 || (args[0].is_a?(::Neo4j::Core::Query) && args.size == 2)) ? args.pop : {}
90
+
91
+ queries(session, options) { append(*args) }[0]
48
92
  end
49
93
 
50
- def queries(&block)
94
+ def queries(session, options = {}, &block)
51
95
  query_builder = QueryBuilder.new
52
96
 
53
97
  query_builder.instance_eval(&block)
54
98
 
55
- query_set(query_builder.queries)
99
+ new_or_current_transaction(session, options[:transaction]) do |tx|
100
+ query_set(tx, query_builder.queries, {commit: !options[:transaction]}.merge(options))
101
+ end
56
102
  end
57
103
 
58
- def query_set(_queries)
59
- fail '#queries not implemented!'
104
+ [:query_set,
105
+ :version,
106
+ :indexes,
107
+ :constraints,
108
+ :connected?].each do |method|
109
+ define_method(method) do |*_args|
110
+ fail "##{method} method not implemented on adaptor!"
111
+ end
60
112
  end
61
113
 
62
- def start_transaction(*_args)
63
- fail '#start_transaction not implemented!'
64
- end
114
+ # If called without a block, returns a Transaction object
115
+ # which can be used to call query/queries/mark_failed/commit
116
+ # If called with a block, the Transaction object is yielded
117
+ # to the block and `commit` is ensured. Any uncaught exceptions
118
+ # will mark the transaction as failed first
119
+ def transaction(session)
120
+ return self.class.transaction_class.new(session) if !block_given?
65
121
 
66
- def end_transaction(*_args)
67
- fail '#end_transaction not implemented!'
68
- end
122
+ begin
123
+ tx = transaction(session)
69
124
 
70
- def transaction_started?(*_args)
71
- fail '#transaction_started? not implemented!'
72
- end
125
+ yield tx
126
+ rescue => e
127
+ tx.mark_failed
73
128
 
74
- def version(*_args)
75
- fail '#version not implemented!'
129
+ raise e
130
+ ensure
131
+ tx.close
132
+ end
76
133
  end
77
134
 
78
- # Schema inspection methods
79
- def indexes_for_label(*_args)
80
- fail '#indexes_for_label not implemented!'
81
- end
135
+ def logger
136
+ return @logger if @logger
82
137
 
83
- def uniqueness_constraints_for_label(*_args)
84
- fail '#uniqueness_constraints_for_label not implemented!'
138
+ @logger = if @options[:logger]
139
+ @options[:logger]
140
+ else
141
+ Logger.new(logger_location).tap do |logger|
142
+ logger.level = logger_level
143
+ end
144
+ end
85
145
  end
86
146
 
147
+ def setup_queries!(queries, transaction, options = {})
148
+ fail 'Query attempted without a connection' if !connected?
149
+ fail "Invalid transaction object: #{transaction.inspect}" if !transaction.is_a?(self.class.transaction_class)
87
150
 
88
- # Uses #start_transaction and #end_transaction to allow
89
- # execution of queries within a block to be part of a
90
- # full transaction
91
- def transaction
92
- start_transaction
93
-
94
- yield
95
- ensure
96
- end_transaction if transaction_started?
151
+ # context option not yet implemented
152
+ self.class.instrument_queries(queries) unless options[:skip_instrumentation]
97
153
  end
98
154
 
99
155
  EMPTY = ''
@@ -101,7 +157,7 @@ module Neo4j
101
157
 
102
158
  instrument(:query, 'neo4j.core.cypher_query', %w(query)) do |_, _start, _finish, _id, payload|
103
159
  query = payload[:query]
104
- params_string = (query.parameters && query.parameters.size > 0 ? "| #{query.parameters.inspect}" : EMPTY)
160
+ params_string = (query.parameters && !query.parameters.empty? ? "| #{query.parameters.inspect}" : EMPTY)
105
161
  cypher = query.pretty_cypher ? NEWLINE_W_SPACES + query.pretty_cypher.gsub(/\n/, NEWLINE_W_SPACES) : query.cypher
106
162
 
107
163
  " #{ANSI::CYAN}#{query.context || 'CYPHER'}#{ANSI::CLEAR} #{cypher} #{params_string}"
@@ -113,6 +169,33 @@ module Neo4j
113
169
  instrument_query(query) {}
114
170
  end
115
171
  end
172
+
173
+ def transaction_class
174
+ fail '.transaction_class method not implemented on adaptor!'
175
+ end
176
+ end
177
+
178
+ private
179
+
180
+ def new_or_current_transaction(session, tx, &block)
181
+ if tx
182
+ yield(tx)
183
+ else
184
+ transaction(session, &block)
185
+ end
186
+ end
187
+
188
+ def validate_query_set!(transaction, _queries, _options = {})
189
+ fail 'Query attempted without a connection' if !connected?
190
+ fail "Invalid transaction object: #{transaction}" if !transaction.is_a?(self.class.transaction_class)
191
+ end
192
+
193
+ def logger_location
194
+ @options[:logger_location] || STDOUT
195
+ end
196
+
197
+ def logger_level
198
+ @options[:logger_level] || Logger::WARN
116
199
  end
117
200
  end
118
201
  end