cql-rb 1.0.0.pre7 → 1.0.0.pre8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/lib/cql/byte_buffer.rb +22 -0
  2. data/lib/cql/client.rb +79 -310
  3. data/lib/cql/client/asynchronous_client.rb +254 -0
  4. data/lib/cql/client/asynchronous_prepared_statement.rb +19 -0
  5. data/lib/cql/client/column_metadata.rb +22 -0
  6. data/lib/cql/client/query_result.rb +34 -0
  7. data/lib/cql/client/result_metadata.rb +31 -0
  8. data/lib/cql/client/synchronous_client.rb +47 -0
  9. data/lib/cql/client/synchronous_prepared_statement.rb +47 -0
  10. data/lib/cql/future.rb +7 -3
  11. data/lib/cql/io.rb +1 -0
  12. data/lib/cql/io/io_reactor.rb +9 -3
  13. data/lib/cql/io/node_connection.rb +2 -2
  14. data/lib/cql/protocol.rb +5 -4
  15. data/lib/cql/protocol/request.rb +23 -0
  16. data/lib/cql/protocol/requests/credentials_request.rb +1 -1
  17. data/lib/cql/protocol/requests/execute_request.rb +13 -84
  18. data/lib/cql/protocol/requests/options_request.rb +1 -1
  19. data/lib/cql/protocol/requests/prepare_request.rb +2 -1
  20. data/lib/cql/protocol/requests/query_request.rb +3 -1
  21. data/lib/cql/protocol/requests/register_request.rb +1 -1
  22. data/lib/cql/protocol/requests/startup_request.rb +1 -2
  23. data/lib/cql/protocol/{response_body.rb → response.rb} +1 -1
  24. data/lib/cql/protocol/responses/authenticate_response.rb +1 -1
  25. data/lib/cql/protocol/responses/error_response.rb +1 -1
  26. data/lib/cql/protocol/responses/ready_response.rb +1 -1
  27. data/lib/cql/protocol/responses/result_response.rb +1 -1
  28. data/lib/cql/protocol/responses/rows_result_response.rb +1 -1
  29. data/lib/cql/protocol/responses/supported_response.rb +1 -1
  30. data/lib/cql/protocol/type_converter.rb +226 -46
  31. data/lib/cql/version.rb +1 -1
  32. data/spec/cql/byte_buffer_spec.rb +38 -0
  33. data/spec/cql/client/asynchronous_client_spec.rb +472 -0
  34. data/spec/cql/client/client_shared.rb +27 -0
  35. data/spec/cql/client/synchronous_client_spec.rb +104 -0
  36. data/spec/cql/client/synchronous_prepared_statement_spec.rb +65 -0
  37. data/spec/cql/future_spec.rb +4 -0
  38. data/spec/cql/io/io_reactor_spec.rb +39 -20
  39. data/spec/cql/protocol/request_spec.rb +17 -0
  40. data/spec/cql/protocol/requests/credentials_request_spec.rb +82 -0
  41. data/spec/cql/protocol/requests/execute_request_spec.rb +174 -0
  42. data/spec/cql/protocol/requests/options_request_spec.rb +24 -0
  43. data/spec/cql/protocol/requests/prepare_request_spec.rb +70 -0
  44. data/spec/cql/protocol/requests/query_request_spec.rb +95 -0
  45. data/spec/cql/protocol/requests/register_request_spec.rb +24 -0
  46. data/spec/cql/protocol/requests/startup_request_spec.rb +29 -0
  47. data/spec/integration/client_spec.rb +26 -19
  48. data/spec/integration/protocol_spec.rb +2 -2
  49. data/spec/integration/regression_spec.rb +1 -1
  50. metadata +35 -9
  51. data/lib/cql/protocol/request_body.rb +0 -15
  52. data/lib/cql/protocol/request_frame.rb +0 -20
  53. data/spec/cql/client_spec.rb +0 -454
  54. data/spec/cql/protocol/request_frame_spec.rb +0 -456
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Cql
4
- VERSION = '1.0.0.pre7'.freeze
4
+ VERSION = '1.0.0.pre8'.freeze
5
5
  end
@@ -264,6 +264,31 @@ module Cql
264
264
  end
265
265
  end
266
266
 
267
+ describe '#update' do
268
+ it 'changes the bytes at the specified location' do
269
+ buffer.append('foo bar')
270
+ buffer.update(4, 'baz')
271
+ buffer.to_s.should == 'foo baz'
272
+ end
273
+
274
+ it 'handles updates after a read' do
275
+ buffer.append('foo bar')
276
+ buffer.read(1)
277
+ buffer.update(3, 'baz')
278
+ buffer.to_s.should == 'oo baz'
279
+ end
280
+
281
+ it 'handles updates after multiple reads and appends' do
282
+ buffer.append('foo bar')
283
+ buffer.read(1)
284
+ buffer.append('x')
285
+ buffer.update(4, 'baz')
286
+ buffer.append('yyyy')
287
+ buffer.read(1)
288
+ buffer.to_s.should == 'o bbazyyyy'
289
+ end
290
+ end
291
+
267
292
  describe '#dup' do
268
293
  it 'returns a copy' do
269
294
  buffer.append('hello world')
@@ -279,6 +304,19 @@ module Cql
279
304
  end
280
305
  end
281
306
 
307
+ describe '#cheap_peek' do
308
+ it 'returns a prefix of the buffer' do
309
+ buffer.append('foo')
310
+ buffer.append('bar')
311
+ buffer.read_byte
312
+ buffer.append('hello')
313
+ x = buffer.cheap_peek
314
+ x.bytesize.should be > 0
315
+ x.bytesize.should be <= buffer.bytesize
316
+ buffer.to_str.should start_with(x)
317
+ end
318
+ end
319
+
282
320
  context 'when reading and appending' do
283
321
  it 'handles heavy churn' do
284
322
  1000.times do
@@ -0,0 +1,472 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'cql/client/client_shared'
5
+
6
+
7
+ module Cql
8
+ module Client
9
+ describe AsynchronousClient do
10
+ let :client do
11
+ described_class.new(connection_options)
12
+ end
13
+
14
+ include_context 'client setup'
15
+
16
+ describe '#connect' do
17
+ it 'connects' do
18
+ client.connect.get
19
+ connections.should have(1).item
20
+ end
21
+
22
+ it 'connects only once' do
23
+ client.connect.get
24
+ client.connect.get
25
+ connections.should have(1).item
26
+ end
27
+
28
+ it 'connects to all hosts' do
29
+ client.close.get
30
+ io_reactor.stop.get
31
+ io_reactor.start.get
32
+
33
+ c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
34
+ c.connect.get
35
+ connections.should have(3).items
36
+ end
37
+
38
+ it 'returns itself' do
39
+ client.connect.get.should equal(client)
40
+ end
41
+
42
+ it 'forwards the host and port' do
43
+ client.connect.get
44
+ connection[:host].should == 'example.com'
45
+ connection[:port].should == 12321
46
+ end
47
+
48
+ it 'sends a startup request' do
49
+ client.connect.get
50
+ last_request.should be_a(Protocol::StartupRequest)
51
+ end
52
+
53
+ it 'sends a startup request to each connection' do
54
+ client.close.get
55
+ io_reactor.stop.get
56
+ io_reactor.start.get
57
+
58
+ c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
59
+ c.connect.get
60
+ connections.each do |cc|
61
+ cc[:requests].last.should be_a(Protocol::StartupRequest)
62
+ end
63
+ end
64
+
65
+ it 'is not in a keyspace' do
66
+ client.connect.get
67
+ client.keyspace.should be_nil
68
+ end
69
+
70
+ it 'changes to the keyspace given as an option' do
71
+ c = described_class.new(connection_options.merge(:keyspace => 'hello_world'))
72
+ c.connect.get
73
+ last_request.should == Protocol::QueryRequest.new('USE hello_world', :one)
74
+ end
75
+
76
+ it 'validates the keyspace name before sending the USE command' do
77
+ c = described_class.new(connection_options.merge(:keyspace => 'system; DROP KEYSPACE system'))
78
+ expect { c.connect.get }.to raise_error(InvalidKeyspaceNameError)
79
+ requests.should_not include(Protocol::QueryRequest.new('USE system; DROP KEYSPACE system', :one))
80
+ end
81
+
82
+ it 're-raises any errors raised' do
83
+ io_reactor.stub(:add_connection).and_raise(ArgumentError)
84
+ expect { client.connect.get }.to raise_error(ArgumentError)
85
+ end
86
+
87
+ it 'is not connected if an error is raised' do
88
+ io_reactor.stub(:add_connection).and_raise(ArgumentError)
89
+ client.connect.get rescue nil
90
+ client.should_not be_connected
91
+ io_reactor.should_not be_running
92
+ end
93
+
94
+ it 'is connected after #connect returns' do
95
+ client.connect.get
96
+ client.should be_connected
97
+ end
98
+
99
+ it 'is not connected while connecting' do
100
+ pending 'the fake reactor needs to be made asynchronous' do
101
+ io_reactor.stop.get
102
+ f = client.connect
103
+ client.should_not be_connected
104
+ io_reactor.start.get
105
+ f.get
106
+ end
107
+ end
108
+
109
+ context 'when the server requests authentication' do
110
+ before do
111
+ io_reactor.queue_response(Protocol::AuthenticateResponse.new('com.example.Auth'))
112
+ end
113
+
114
+ it 'sends credentials' do
115
+ client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
116
+ client.connect.get
117
+ last_request.should == Protocol::CredentialsRequest.new('username' => 'foo', 'password' => 'bar')
118
+ end
119
+
120
+ it 'raises an error when no credentials have been given' do
121
+ client = described_class.new(connection_options)
122
+ expect { client.connect.get }.to raise_error(AuthenticationError)
123
+ end
124
+
125
+ it 'raises an error when the server responds with an error to the credentials request' do
126
+ io_reactor.queue_response(Protocol::ErrorResponse.new(256, 'No way, José'))
127
+ client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
128
+ expect { client.connect.get }.to raise_error(AuthenticationError)
129
+ end
130
+
131
+ it 'shuts down the client when there is an authentication error' do
132
+ io_reactor.queue_response(Protocol::ErrorResponse.new(256, 'No way, José'))
133
+ client = described_class.new(connection_options.merge(credentials: {'username' => 'foo', 'password' => 'bar'}))
134
+ client.connect.get rescue nil
135
+ client.should_not be_connected
136
+ io_reactor.should_not be_running
137
+ end
138
+ end
139
+ end
140
+
141
+ describe '#close' do
142
+ it 'closes the connection' do
143
+ client.connect.get
144
+ client.close.get
145
+ io_reactor.should_not be_running
146
+ end
147
+
148
+ it 'does nothing when called before #connect' do
149
+ client.close.get
150
+ end
151
+
152
+ it 'accepts multiple calls to #close' do
153
+ client.connect.get
154
+ client.close.get
155
+ client.close.get
156
+ end
157
+
158
+ it 'returns itself' do
159
+ client.connect.get.close.get.should equal(client)
160
+ end
161
+ end
162
+
163
+ describe '#use' do
164
+ before do
165
+ client.connect.get
166
+ end
167
+
168
+ it 'executes a USE query' do
169
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'))
170
+ client.use('system').get
171
+ last_request.should == Protocol::QueryRequest.new('USE system', :one)
172
+ end
173
+
174
+ it 'executes a USE query for each connection' do
175
+ client.close.get
176
+ io_reactor.stop.get
177
+ io_reactor.start.get
178
+
179
+ c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
180
+ c.connect.get
181
+
182
+ c.use('system').get
183
+ last_requests = connections.select { |c| c[:host] =~ /^h\d\.example\.com$/ }.sort_by { |c| c[:host] }.map { |c| c[:requests].last }
184
+ last_requests.should == [
185
+ Protocol::QueryRequest.new('USE system', :one),
186
+ Protocol::QueryRequest.new('USE system', :one),
187
+ Protocol::QueryRequest.new('USE system', :one)
188
+ ]
189
+ end
190
+
191
+ it 'knows which keyspace it changed to' do
192
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'))
193
+ client.use('system').get
194
+ client.keyspace.should == 'system'
195
+ end
196
+
197
+ it 'raises an error if the keyspace name is not valid' do
198
+ expect { client.use('system; DROP KEYSPACE system').get }.to raise_error(InvalidKeyspaceNameError)
199
+ end
200
+ end
201
+
202
+ describe '#execute' do
203
+ before do
204
+ client.connect.get
205
+ end
206
+
207
+ it 'asks the connection to execute the query' do
208
+ client.execute('UPDATE stuff SET thing = 1 WHERE id = 3').get
209
+ last_request.should == Protocol::QueryRequest.new('UPDATE stuff SET thing = 1 WHERE id = 3', :quorum)
210
+ end
211
+
212
+ it 'uses the specified consistency' do
213
+ client.execute('UPDATE stuff SET thing = 1 WHERE id = 3', :three).get
214
+ last_request.should == Protocol::QueryRequest.new('UPDATE stuff SET thing = 1 WHERE id = 3', :three)
215
+ end
216
+
217
+ context 'with a void CQL query' do
218
+ it 'returns nil' do
219
+ io_reactor.queue_response(Protocol::VoidResultResponse.new)
220
+ result = client.execute('UPDATE stuff SET thing = 1 WHERE id = 3').get
221
+ result.should be_nil
222
+ end
223
+ end
224
+
225
+ context 'with a USE query' do
226
+ it 'returns nil' do
227
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'))
228
+ result = client.execute('USE system').get
229
+ result.should be_nil
230
+ end
231
+
232
+ it 'knows which keyspace it changed to' do
233
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'))
234
+ client.execute('USE system').get
235
+ client.keyspace.should == 'system'
236
+ end
237
+
238
+ it 'detects that one connection changed to a keyspace and changes the others too' do
239
+ client.close.get
240
+ io_reactor.stop.get
241
+ io_reactor.start.get
242
+
243
+ c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
244
+ c.connect.get
245
+
246
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'), connections.find { |c| c[:host] == 'h1.example.com' }[:host])
247
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'), connections.find { |c| c[:host] == 'h2.example.com' }[:host])
248
+ io_reactor.queue_response(Protocol::SetKeyspaceResultResponse.new('system'), connections.find { |c| c[:host] == 'h3.example.com' }[:host])
249
+
250
+ c.execute('USE system', :one).get
251
+ c.keyspace.should == 'system'
252
+
253
+ last_requests = connections.select { |c| c[:host] =~ /^h\d\.example\.com$/ }.sort_by { |c| c[:host] }.map { |c| c[:requests].last }
254
+ last_requests.should == [
255
+ Protocol::QueryRequest.new('USE system', :one),
256
+ Protocol::QueryRequest.new('USE system', :one),
257
+ Protocol::QueryRequest.new('USE system', :one)
258
+ ]
259
+ end
260
+ end
261
+
262
+ context 'with an SELECT query' do
263
+ let :rows do
264
+ [['xyz', 'abc'], ['abc', 'xyz'], ['123', 'xyz']]
265
+ end
266
+
267
+ let :metadata do
268
+ [['thingies', 'things', 'thing', :text], ['thingies', 'things', 'item', :text]]
269
+ end
270
+
271
+ let :result do
272
+ io_reactor.queue_response(Protocol::RowsResultResponse.new(rows, metadata))
273
+ client.execute('SELECT * FROM things').get
274
+ end
275
+
276
+ it 'returns an Enumerable of rows' do
277
+ row_count = 0
278
+ result.each do |row|
279
+ row_count += 1
280
+ end
281
+ row_count.should == 3
282
+ end
283
+
284
+ context 'with metadata that' do
285
+ it 'has keyspace, table and type information' do
286
+ result.metadata['item'].keyspace.should == 'thingies'
287
+ result.metadata['item'].table.should == 'things'
288
+ result.metadata['item'].column_name.should == 'item'
289
+ result.metadata['item'].type.should == :text
290
+ end
291
+
292
+ it 'is an Enumerable' do
293
+ result.metadata.map(&:type).should == [:text, :text]
294
+ end
295
+
296
+ it 'is splattable' do
297
+ ks, table, col, type = result.metadata['thing']
298
+ ks.should == 'thingies'
299
+ table.should == 'things'
300
+ col.should == 'thing'
301
+ type.should == :text
302
+ end
303
+ end
304
+ end
305
+
306
+ context 'when there is an error creating the request' do
307
+ it 'returns a failed future' do
308
+ f = client.execute('SELECT * FROM stuff', :foo)
309
+ expect { f.get }.to raise_error(ArgumentError)
310
+ end
311
+ end
312
+
313
+ context 'when the response is an error' do
314
+ it 'raises an error' do
315
+ io_reactor.queue_response(Protocol::ErrorResponse.new(0xabcd, 'Blurgh'))
316
+ expect { client.execute('SELECT * FROM things').get }.to raise_error(QueryError, 'Blurgh')
317
+ end
318
+
319
+ it 'decorates the error with the CQL that caused it' do
320
+ io_reactor.queue_response(Protocol::ErrorResponse.new(0xabcd, 'Blurgh'))
321
+ begin
322
+ client.execute('SELECT * FROM things').get
323
+ rescue QueryError => e
324
+ e.cql.should == 'SELECT * FROM things'
325
+ else
326
+ fail('No error was raised')
327
+ end
328
+ end
329
+ end
330
+ end
331
+
332
+ describe '#prepare' do
333
+ let :id do
334
+ 'A' * 32
335
+ end
336
+
337
+ let :metadata do
338
+ [['stuff', 'things', 'item', :varchar]]
339
+ end
340
+
341
+ before do
342
+ client.connect.get
343
+ end
344
+
345
+ it 'sends a prepare request' do
346
+ client.prepare('SELECT * FROM system.peers').get
347
+ last_request.should == Protocol::PrepareRequest.new('SELECT * FROM system.peers')
348
+ end
349
+
350
+ it 'returns a prepared statement' do
351
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new('A' * 32, [['stuff', 'things', 'item', :varchar]]))
352
+ statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
353
+ statement.should_not be_nil
354
+ end
355
+
356
+ it 'executes a prepared statement' do
357
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
358
+ statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
359
+ statement.execute('foo').get
360
+ last_request.should == Protocol::ExecuteRequest.new(id, metadata, ['foo'], :quorum)
361
+ end
362
+
363
+ it 'returns a prepared statement that knows the metadata' do
364
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
365
+ statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
366
+ statement.metadata['item'].type == :varchar
367
+ end
368
+
369
+ it 'executes a prepared statement with a specific consistency level' do
370
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
371
+ statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
372
+ statement.execute('thing', :local_quorum).get
373
+ last_request.should == Protocol::ExecuteRequest.new(id, metadata, ['thing'], :local_quorum)
374
+ end
375
+
376
+ it 'executes a prepared statement using the right connection' do
377
+ client.close.get
378
+ io_reactor.stop.get
379
+ io_reactor.start.get
380
+
381
+ c = described_class.new(connection_options.merge(host: 'h1.example.com,h2.example.com,h3.example.com'))
382
+ c.connect.get
383
+
384
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new('A' * 32, metadata))
385
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new('B' * 32, metadata))
386
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new('C' * 32, metadata))
387
+
388
+ statement1 = c.prepare('SELECT * FROM stuff.things WHERE item = ?').get
389
+ statement1_connection = io_reactor.last_used_connection
390
+ statement2 = c.prepare('SELECT * FROM stuff.things WHERE item = ?').get
391
+ statement2_connection = io_reactor.last_used_connection
392
+ statement3 = c.prepare('SELECT * FROM stuff.things WHERE item = ?').get
393
+ statement3_connection = io_reactor.last_used_connection
394
+
395
+ io_reactor.queue_response(Protocol::RowsResultResponse.new([{'thing' => 'foo1'}], metadata), statement1_connection[:host])
396
+ io_reactor.queue_response(Protocol::RowsResultResponse.new([{'thing' => 'foo2'}], metadata), statement2_connection[:host])
397
+ io_reactor.queue_response(Protocol::RowsResultResponse.new([{'thing' => 'foo3'}], metadata), statement3_connection[:host])
398
+
399
+ statement1.execute('foo').get.first.should == {'thing' => 'foo1'}
400
+ statement2.execute('foo').get.first.should == {'thing' => 'foo2'}
401
+ statement3.execute('foo').get.first.should == {'thing' => 'foo3'}
402
+ end
403
+
404
+ context 'when there is an error creating the request' do
405
+ it 'returns a failed future' do
406
+ f = client.prepare(nil)
407
+ expect { f.get }.to raise_error(ArgumentError)
408
+ end
409
+ end
410
+
411
+ context 'when there is an error preparing the request' do
412
+ it 'returns a failed future' do
413
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new(id, metadata))
414
+ statement = client.prepare('SELECT * FROM stuff.things WHERE item = ?').get
415
+ f = statement.execute
416
+ expect { f.get }.to raise_error(ArgumentError)
417
+ end
418
+ end
419
+ end
420
+
421
+ context 'when not connected' do
422
+ it 'is not connected before #connect has been called' do
423
+ client.should_not be_connected
424
+ end
425
+
426
+ it 'is not connected after #close has been called' do
427
+ client.connect.get
428
+ client.close.get
429
+ client.should_not be_connected
430
+ end
431
+
432
+ it 'complains when #use is called before #connect' do
433
+ expect { client.use('system').get }.to raise_error(NotConnectedError)
434
+ end
435
+
436
+ it 'complains when #use is called after #close' do
437
+ client.connect.get
438
+ client.close.get
439
+ expect { client.use('system').get }.to raise_error(NotConnectedError)
440
+ end
441
+
442
+ it 'complains when #execute is called before #connect' do
443
+ expect { client.execute('DELETE FROM stuff WHERE id = 3').get }.to raise_error(NotConnectedError)
444
+ end
445
+
446
+ it 'complains when #execute is called after #close' do
447
+ client.connect.get
448
+ client.close.get
449
+ expect { client.execute('DELETE FROM stuff WHERE id = 3').get }.to raise_error(NotConnectedError)
450
+ end
451
+
452
+ it 'complains when #prepare is called before #connect' do
453
+ expect { client.prepare('DELETE FROM stuff WHERE id = 3').get }.to raise_error(NotConnectedError)
454
+ end
455
+
456
+ it 'complains when #prepare is called after #close' do
457
+ client.connect.get
458
+ client.close.get
459
+ expect { client.prepare('DELETE FROM stuff WHERE id = 3').get }.to raise_error(NotConnectedError)
460
+ end
461
+
462
+ it 'complains when #execute of a prepared statement is called after #close' do
463
+ client.connect.get
464
+ io_reactor.queue_response(Protocol::PreparedResultResponse.new('A' * 32, []))
465
+ statement = client.prepare('DELETE FROM stuff WHERE id = 3').get
466
+ client.close.get
467
+ expect { statement.execute.get }.to raise_error(NotConnectedError)
468
+ end
469
+ end
470
+ end
471
+ end
472
+ end