cql-rb 1.2.2 → 2.0.0.pre0
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 +4 -4
- data/.yardopts +4 -0
- data/README.md +139 -17
- data/lib/cql/client.rb +237 -8
- data/lib/cql/client/asynchronous_client.rb +138 -54
- data/lib/cql/client/asynchronous_prepared_statement.rb +41 -6
- data/lib/cql/client/authenticators.rb +46 -0
- data/lib/cql/client/batch.rb +115 -0
- data/lib/cql/client/connector.rb +255 -0
- data/lib/cql/client/execute_options_decoder.rb +25 -9
- data/lib/cql/client/keyspace_changer.rb +5 -5
- data/lib/cql/client/peer_discovery.rb +33 -0
- data/lib/cql/client/query_result.rb +124 -1
- data/lib/cql/client/request_runner.rb +4 -2
- data/lib/cql/client/synchronous_client.rb +14 -2
- data/lib/cql/client/synchronous_prepared_statement.rb +19 -1
- data/lib/cql/future.rb +97 -50
- data/lib/cql/io/connection.rb +0 -1
- data/lib/cql/io/io_reactor.rb +1 -1
- data/lib/cql/protocol.rb +8 -1
- data/lib/cql/protocol/cql_protocol_handler.rb +2 -2
- data/lib/cql/protocol/decoding.rb +10 -15
- data/lib/cql/protocol/frame_decoder.rb +2 -1
- data/lib/cql/protocol/frame_encoder.rb +5 -4
- data/lib/cql/protocol/requests/auth_response_request.rb +31 -0
- data/lib/cql/protocol/requests/batch_request.rb +59 -0
- data/lib/cql/protocol/requests/credentials_request.rb +1 -1
- data/lib/cql/protocol/requests/execute_request.rb +45 -17
- data/lib/cql/protocol/requests/options_request.rb +1 -1
- data/lib/cql/protocol/requests/prepare_request.rb +1 -1
- data/lib/cql/protocol/requests/query_request.rb +97 -5
- data/lib/cql/protocol/requests/register_request.rb +1 -1
- data/lib/cql/protocol/requests/startup_request.rb +4 -4
- data/lib/cql/protocol/response.rb +2 -2
- data/lib/cql/protocol/responses/auth_challenge_response.rb +25 -0
- data/lib/cql/protocol/responses/auth_success_response.rb +25 -0
- data/lib/cql/protocol/responses/authenticate_response.rb +1 -1
- data/lib/cql/protocol/responses/detailed_error_response.rb +1 -1
- data/lib/cql/protocol/responses/error_response.rb +3 -2
- data/lib/cql/protocol/responses/event_response.rb +3 -2
- data/lib/cql/protocol/responses/prepared_result_response.rb +10 -6
- data/lib/cql/protocol/responses/raw_rows_result_response.rb +27 -0
- data/lib/cql/protocol/responses/ready_response.rb +1 -1
- data/lib/cql/protocol/responses/result_response.rb +2 -2
- data/lib/cql/protocol/responses/rows_result_response.rb +43 -23
- data/lib/cql/protocol/responses/schema_change_event_response.rb +1 -1
- data/lib/cql/protocol/responses/schema_change_result_response.rb +1 -1
- data/lib/cql/protocol/responses/set_keyspace_result_response.rb +1 -1
- data/lib/cql/protocol/responses/status_change_event_response.rb +1 -1
- data/lib/cql/protocol/responses/supported_response.rb +1 -1
- data/lib/cql/protocol/responses/void_result_response.rb +1 -1
- data/lib/cql/protocol/type_converter.rb +2 -2
- data/lib/cql/uuid.rb +2 -2
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +493 -50
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +193 -11
- data/spec/cql/client/authenticators_spec.rb +56 -0
- data/spec/cql/client/batch_spec.rb +277 -0
- data/spec/cql/client/connector_spec.rb +606 -0
- data/spec/cql/client/execute_options_decoder_spec.rb +95 -0
- data/spec/cql/client/keyspace_changer_spec.rb +8 -8
- data/spec/cql/client/peer_discovery_spec.rb +92 -0
- data/spec/cql/client/query_result_spec.rb +352 -0
- data/spec/cql/client/request_runner_spec.rb +31 -5
- data/spec/cql/client/synchronous_client_spec.rb +44 -1
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +63 -1
- data/spec/cql/future_spec.rb +50 -2
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +16 -5
- data/spec/cql/protocol/decoding_spec.rb +16 -6
- data/spec/cql/protocol/encoding_spec.rb +3 -1
- data/spec/cql/protocol/frame_encoder_spec.rb +99 -50
- data/spec/cql/protocol/requests/auth_response_request_spec.rb +62 -0
- data/spec/cql/protocol/requests/batch_request_spec.rb +155 -0
- data/spec/cql/protocol/requests/credentials_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/execute_request_spec.rb +184 -71
- data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/prepare_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/query_request_spec.rb +255 -32
- data/spec/cql/protocol/requests/register_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/startup_request_spec.rb +12 -6
- data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +31 -0
- data/spec/cql/protocol/responses/auth_success_response_spec.rb +31 -0
- data/spec/cql/protocol/responses/authenticate_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/detailed_error_response_spec.rb +14 -7
- data/spec/cql/protocol/responses/error_response_spec.rb +4 -2
- data/spec/cql/protocol/responses/event_response_spec.rb +7 -4
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +89 -34
- data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +66 -0
- data/spec/cql/protocol/responses/ready_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/result_response_spec.rb +19 -7
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +56 -11
- data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/status_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/supported_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +2 -1
- data/spec/cql/protocol/responses/void_result_response_spec.rb +1 -1
- data/spec/cql/protocol/type_converter_spec.rb +21 -4
- data/spec/cql/uuid_spec.rb +10 -3
- data/spec/integration/client_spec.rb +251 -28
- data/spec/integration/protocol_spec.rb +213 -62
- data/spec/integration/regression_spec.rb +4 -1
- data/spec/integration/uuid_spec.rb +4 -1
- data/spec/support/fake_io_reactor.rb +5 -5
- metadata +36 -7
- data/lib/cql/client/connection_helper.rb +0 -181
- data/spec/cql/client/connection_helper_spec.rb +0 -429
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Cql
|
7
|
+
module Client
|
8
|
+
describe ExecuteOptionsDecoder do
|
9
|
+
let :decoder do
|
10
|
+
described_class.new(:two)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#decode_options' do
|
14
|
+
it 'returns the default consistency' do
|
15
|
+
options = decoder.decode_options({})
|
16
|
+
options.should include(consistency: :two)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns the default consistency when given no options' do
|
20
|
+
options = decoder.decode_options
|
21
|
+
options.should include(consistency: :two)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns the default consistency when given nil' do
|
25
|
+
options = decoder.decode_options(nil)
|
26
|
+
options.should include(consistency: :two)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'uses the consistency given in the options' do
|
30
|
+
options = decoder.decode_options(consistency: :three)
|
31
|
+
options.should include(consistency: :three)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'uses the consistency given as a symbol' do
|
35
|
+
options = decoder.decode_options(:three)
|
36
|
+
options.should include(consistency: :three)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'defaults to no serial consistency' do
|
40
|
+
options = decoder.decode_options({})
|
41
|
+
options.should_not have_key(:serial_consistency)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'uses the serial consistency given in the options' do
|
45
|
+
options = decoder.decode_options(serial_consistency: :local_serial)
|
46
|
+
options.should include(serial_consistency: :local_serial)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'defaults to no tracing' do
|
50
|
+
options = decoder.decode_options({})
|
51
|
+
options.should_not have_key(:trace)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'uses the tracing value given in the options' do
|
55
|
+
options = decoder.decode_options(trace: true)
|
56
|
+
options.should include(trace: true)
|
57
|
+
options = decoder.decode_options(trace: false)
|
58
|
+
options.should include(trace: false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'defaults to no timeout' do
|
62
|
+
options = decoder.decode_options({})
|
63
|
+
options.should_not have_key(:timeout)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'uses the timeout value given in the options' do
|
67
|
+
options = decoder.decode_options(timeout: 3)
|
68
|
+
options.should include(timeout: 3)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when called with multiple options' do
|
72
|
+
it 'merges the options' do
|
73
|
+
options = decoder.decode_options({:tracing => true, :timeout => 3}, {:consistency => :quorum, :timeout => 4})
|
74
|
+
options.should eql(tracing: true, timeout: 4, consistency: :quorum)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'uses the default consistency' do
|
78
|
+
options = decoder.decode_options({tracing: true, timeout: 3}, {:timeout => 4})
|
79
|
+
options.should eql(tracing: true, timeout: 4, consistency: :two)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'accepts nil' do
|
83
|
+
options = decoder.decode_options(nil, {tracing: true, timeout: 3}, nil, {:timeout => 4})
|
84
|
+
options.should eql(tracing: true, timeout: 4, consistency: :two)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'accepts consistencies given as symbols' do
|
88
|
+
options = decoder.decode_options({tracing: true, timeout: 3}, :quorum)
|
89
|
+
options.should eql(tracing: true, timeout: 3, consistency: :quorum)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -16,31 +16,31 @@ module Cql
|
|
16
16
|
|
17
17
|
describe '#use_keyspace' do
|
18
18
|
it 'sends a query request with a USE statement' do
|
19
|
-
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE important_stuff', :one), nil).and_return(Future.resolved)
|
20
|
-
f = keyspace_changer.use_keyspace('important_stuff'
|
19
|
+
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE important_stuff', nil, nil, :one), nil).and_return(Future.resolved)
|
20
|
+
f = keyspace_changer.use_keyspace(connection, 'important_stuff')
|
21
21
|
connection.should have_received(:send_request)
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'accepts quoted keyspace names' do
|
25
|
-
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE "ImportantStuff"', :one), nil).and_return(Future.resolved)
|
26
|
-
f = keyspace_changer.use_keyspace('"ImportantStuff"'
|
25
|
+
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE "ImportantStuff"', nil, nil, :one), nil).and_return(Future.resolved)
|
26
|
+
f = keyspace_changer.use_keyspace(connection, '"ImportantStuff"')
|
27
27
|
connection.should have_received(:send_request)
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'returns a future that' do
|
31
31
|
it 'immediately resolves to the given connection when the keyspace is nil' do
|
32
|
-
f = keyspace_changer.use_keyspace(
|
32
|
+
f = keyspace_changer.use_keyspace(connection, nil)
|
33
33
|
f.value.should equal(connection)
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'fails with an InvalidKeyspaceNameError when the keyspace name is invalid' do
|
37
|
-
f = keyspace_changer.use_keyspace('TRUNCATE important_stuff'
|
37
|
+
f = keyspace_changer.use_keyspace(connection, 'TRUNCATE important_stuff')
|
38
38
|
expect { f.value }.to raise_error(InvalidKeyspaceNameError)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'resolves to the given connection' do
|
42
|
-
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE important_stuff', :one), nil).and_return(Future.resolved)
|
43
|
-
f = keyspace_changer.use_keyspace('important_stuff'
|
42
|
+
connection.stub(:send_request).with(Protocol::QueryRequest.new('USE important_stuff', nil, nil, :one), nil).and_return(Future.resolved)
|
43
|
+
f = keyspace_changer.use_keyspace(connection, 'important_stuff')
|
44
44
|
f.value.should equal(connection)
|
45
45
|
end
|
46
46
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Cql
|
7
|
+
module Client
|
8
|
+
describe PeerDiscovery do
|
9
|
+
let :peer_discovery do
|
10
|
+
described_class.new(seed_connections)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#new_hosts' do
|
14
|
+
let :seed_connections do
|
15
|
+
[
|
16
|
+
FakeConnection.new('host0', 9042, 5, {:data_center => 'dc0', :host_id => Uuid.new('00000000-0000-0000-0000-000000000000')}),
|
17
|
+
FakeConnection.new('host1', 9042, 5, {:data_center => 'dc0', :host_id => Uuid.new('11111111-1111-1111-1111-111111111111')}),
|
18
|
+
FakeConnection.new('host2', 9042, 5, {:data_center => 'dc0', :host_id => Uuid.new('22222222-2222-2222-2222-222222222222')}),
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
let :peer_metadata do
|
23
|
+
[
|
24
|
+
['system', 'peers', 'peer', :inet],
|
25
|
+
['system', 'peers', 'data_center', :varchar],
|
26
|
+
['system', 'peers', 'host_id', :uuid],
|
27
|
+
['system', 'peers', 'rpc_address', :inet],
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
let :peer_rows do
|
32
|
+
[
|
33
|
+
{'peer' => IPAddr.new('2.0.0.0'), 'rpc_address' => IPAddr.new('1.0.0.0'), 'data_center' => 'dc0', 'host_id' => Uuid.new('00000000-0000-0000-0000-000000000000')},
|
34
|
+
{'peer' => IPAddr.new('2.0.0.1'), 'rpc_address' => IPAddr.new('1.0.0.1'), 'data_center' => 'dc0', 'host_id' => Uuid.new('11111111-1111-1111-1111-111111111111')},
|
35
|
+
{'peer' => IPAddr.new('2.0.0.2'), 'rpc_address' => IPAddr.new('1.0.0.2'), 'data_center' => 'dc0', 'host_id' => Uuid.new('22222222-2222-2222-2222-222222222222')},
|
36
|
+
{'peer' => IPAddr.new('2.0.0.3'), 'rpc_address' => IPAddr.new('1.0.0.3'), 'data_center' => 'dc0', 'host_id' => Uuid.new('33333333-3333-3333-3333-333333333333')},
|
37
|
+
{'peer' => IPAddr.new('2.0.0.4'), 'rpc_address' => IPAddr.new('1.0.0.4'), 'data_center' => 'dc0', 'host_id' => Uuid.new('44444444-4444-4444-4444-444444444444')},
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
let :peer_rows_response do
|
42
|
+
Protocol::RowsResultResponse.new(peer_rows, peer_metadata, nil, nil)
|
43
|
+
end
|
44
|
+
|
45
|
+
before do
|
46
|
+
seed_connections.each do |connection|
|
47
|
+
connection.handle_request do |request|
|
48
|
+
peer_rows_response
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'selects all rows from the "peers" system table' do
|
54
|
+
peer_discovery.new_hosts.value
|
55
|
+
selected_connection = seed_connections.find { |c| c.requests.any? }
|
56
|
+
request = selected_connection.requests.first
|
57
|
+
columns, table = request.cql.scan(/SELECT (.*) FROM (\S+)/).flatten
|
58
|
+
table.should == 'system.peers'
|
59
|
+
columns.should include('peer')
|
60
|
+
columns.should include('data_center')
|
61
|
+
columns.should include('host_id')
|
62
|
+
columns.should include('rpc_address')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns a future that resolves to the addresses of all peers that were not already in the set of seed nodes' do
|
66
|
+
new_hosts = peer_discovery.new_hosts
|
67
|
+
new_hosts.value.should == %w[1.0.0.3 1.0.0.4]
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'returns an empty list of addresses when there are no peers that are not in the set of seed nodes' do
|
71
|
+
peer_rows.pop(2)
|
72
|
+
new_hosts = peer_discovery.new_hosts
|
73
|
+
new_hosts.value.should be_empty
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns the value of the "peer" column when the "rpc_address" column contains "0.0.0.0"' do
|
77
|
+
peer_rows.each do |row|
|
78
|
+
row['rpc_address'] = IPAddr.new('0.0.0.0')
|
79
|
+
end
|
80
|
+
new_hosts = peer_discovery.new_hosts
|
81
|
+
new_hosts.value.should == %w[2.0.0.3 2.0.0.4]
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'only returns addresses to nodes that are in the same data centers as the seed nodes' do
|
85
|
+
peer_rows[3]['data_center'] = 'dc1'
|
86
|
+
new_hosts = peer_discovery.new_hosts
|
87
|
+
new_hosts.value.should == %w[1.0.0.4]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,352 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Cql
|
7
|
+
module Client
|
8
|
+
shared_context 'query_result_setup' do
|
9
|
+
let :metadata do
|
10
|
+
[
|
11
|
+
['ks', 'tbl', 'col1', :varchar],
|
12
|
+
['ks', 'tbl', 'col2', :double],
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
let :trace_id do
|
17
|
+
double(:trace_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
let :rows do
|
21
|
+
[double(:row1), double(:row2), double(:row3)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
shared_examples 'query_result_shared' do
|
26
|
+
describe '#metadata' do
|
27
|
+
it 'wraps the raw metadata in a ResultMetadata' do
|
28
|
+
result.metadata['col1'].should == ColumnMetadata.new('ks', 'tbl', 'col1', :varchar)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#each' do
|
33
|
+
it 'yields each row' do
|
34
|
+
yielded_rows = []
|
35
|
+
result.each { |r| yielded_rows << r }
|
36
|
+
yielded_rows.should == rows
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can be iterated multiple times' do
|
40
|
+
yielded_rows = []
|
41
|
+
result.each { |r| yielded_rows << r }
|
42
|
+
result.each { |r| yielded_rows << r }
|
43
|
+
yielded_rows.should == rows + rows
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'is aliased as #each_row' do
|
47
|
+
result.each_row { }
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns an Enumerable when no block is given' do
|
51
|
+
result.each.to_a.should == rows
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when used as an Enumerable' do
|
56
|
+
before do
|
57
|
+
rows.each_with_index { |r, i| r.stub(:[]).with('col2').and_return(i.to_f) }
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'transforms the rows' do
|
61
|
+
result.map { |r| r['col2'] * 2 }.should == [0.0, 2.0, 4.0]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'filters the rows' do
|
65
|
+
result.select { |r| r['col2'] > 0 }.should == rows.drop(1)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe QueryResult do
|
71
|
+
let :result do
|
72
|
+
described_class.new(metadata, rows, trace_id, nil)
|
73
|
+
end
|
74
|
+
|
75
|
+
include_context 'query_result_setup'
|
76
|
+
include_examples 'query_result_shared'
|
77
|
+
|
78
|
+
describe '#empty?' do
|
79
|
+
it 'returns true when there are no rows' do
|
80
|
+
described_class.new(metadata, [], nil, nil).should be_empty
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns false when there are rows' do
|
84
|
+
result.should_not be_empty
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe LazyQueryResult do
|
90
|
+
let :result do
|
91
|
+
described_class.new(metadata, lazy_rows, trace_id, nil)
|
92
|
+
end
|
93
|
+
|
94
|
+
let :lazy_rows do
|
95
|
+
double(:lazy_rows)
|
96
|
+
end
|
97
|
+
|
98
|
+
include_context 'query_result_setup'
|
99
|
+
|
100
|
+
before do
|
101
|
+
lazy_rows.stub(:rows).and_return(nil)
|
102
|
+
lazy_rows.stub(:materialize) do |md|
|
103
|
+
raise '#materialize called twice' if lazy_rows.rows
|
104
|
+
md.should == metadata
|
105
|
+
lazy_rows.stub(:rows).and_return(rows)
|
106
|
+
rows
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
include_examples 'query_result_shared'
|
111
|
+
|
112
|
+
describe '#empty?' do
|
113
|
+
it 'returns true when there are no rows' do
|
114
|
+
lazy_rows.stub(:materialize) do
|
115
|
+
lazy_rows.stub(:rows).and_return([])
|
116
|
+
[]
|
117
|
+
end
|
118
|
+
result.should be_empty
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'returns false when there are rows' do
|
122
|
+
result.should_not be_empty
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
shared_examples 'paged_query_result' do
|
128
|
+
let :metadata do
|
129
|
+
ResultMetadata.new([['ks', 'tbl', 'col1', :varchar], ['ks', 'tbl', 'col2', :double]])
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#metadata' do
|
133
|
+
it 'delegates to the wrapped result' do
|
134
|
+
query_result.stub(:metadata).and_return(metadata)
|
135
|
+
paged_query_result.metadata.should == metadata
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#trace_id' do
|
140
|
+
it 'delegates to the wrapped result' do
|
141
|
+
query_result.stub(:trace_id).and_return('foobaz')
|
142
|
+
paged_query_result.trace_id.should == 'foobaz'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#paging_state' do
|
147
|
+
it 'delegates to the wrapped result' do
|
148
|
+
query_result.stub(:paging_state).and_return('foobaz')
|
149
|
+
paged_query_result.paging_state.should == 'foobaz'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#empty?' do
|
154
|
+
it 'delegates to the wrapped result' do
|
155
|
+
query_result.stub(:empty?).and_return(true)
|
156
|
+
paged_query_result.should be_empty
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#each' do
|
161
|
+
it 'delegates to the wrapped result' do
|
162
|
+
query_result.stub(:each).and_yield(:row1).and_yield(:row2)
|
163
|
+
rows = paged_query_result.each_with_object([]) { |row, rows| rows << row }
|
164
|
+
rows.should == [:row1, :row2]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
shared_examples 'asynchronous_paged_query_result' do
|
170
|
+
include_examples 'paged_query_result'
|
171
|
+
|
172
|
+
describe '#last_page?' do
|
173
|
+
it 'returns true when the result has no paging state' do
|
174
|
+
query_result.stub(:paging_state).and_return(nil)
|
175
|
+
paged_query_result.should be_last_page
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'returns false when the result has a paging state' do
|
179
|
+
paged_query_result.should_not be_last_page
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe AsynchronousQueryPagedQueryResult do
|
185
|
+
let :paged_query_result do
|
186
|
+
described_class.new(client, request, query_result, options)
|
187
|
+
end
|
188
|
+
|
189
|
+
let :client do
|
190
|
+
double(:client)
|
191
|
+
end
|
192
|
+
|
193
|
+
let :request do
|
194
|
+
double(:request, cql: 'SELECT * FROM something WHERE id = ?', values: ['foo'])
|
195
|
+
end
|
196
|
+
|
197
|
+
let :query_result do
|
198
|
+
double(:query_result, paging_state: 'thepagingstate')
|
199
|
+
end
|
200
|
+
|
201
|
+
let :options do
|
202
|
+
{:trace => true, :timeout => 3}
|
203
|
+
end
|
204
|
+
|
205
|
+
include_examples 'asynchronous_paged_query_result'
|
206
|
+
|
207
|
+
describe '#next_page' do
|
208
|
+
let :next_query_result do
|
209
|
+
double(:next_query_result, paging_state: 'thenextpagingstate')
|
210
|
+
end
|
211
|
+
|
212
|
+
before do
|
213
|
+
client.stub(:execute).and_return(Future.resolved(next_query_result))
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'calls the client and passes the paging state' do
|
217
|
+
paged_query_result.next_page.value
|
218
|
+
client.should have_received(:execute).with(anything, anything, hash_including(paging_state: 'thepagingstate'))
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'calls the client and passes the options' do
|
222
|
+
paged_query_result.next_page.value
|
223
|
+
client.should have_received(:execute).with(anything, anything, hash_including(options))
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'calls the client and passes the CQL' do
|
227
|
+
paged_query_result.next_page.value
|
228
|
+
client.should have_received(:execute).with(request.cql, anything, anything)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'calls the client and passes the bound values' do
|
232
|
+
paged_query_result.next_page.value
|
233
|
+
client.should have_received(:execute).with(anything, 'foo', anything)
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'handles the case when there are multiple bound values' do
|
237
|
+
request.stub(:values).and_return(['foo', 3, 'bar', 4])
|
238
|
+
paged_query_result.next_page.value
|
239
|
+
client.should have_received(:execute).with(anything, 'foo', 3, 'bar', 4, anything)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'handles the case when there are no bound values' do
|
243
|
+
request.stub(:values).and_return(nil)
|
244
|
+
paged_query_result.next_page.value
|
245
|
+
client.should have_received(:execute).with(request.cql, an_instance_of(Hash))
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'returns the result of the call' do
|
249
|
+
f = paged_query_result.next_page
|
250
|
+
f.value.should equal(next_query_result)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe AsynchronousPreparedPagedQueryResult do
|
256
|
+
let :paged_query_result do
|
257
|
+
described_class.new(statement, request, query_result, options)
|
258
|
+
end
|
259
|
+
|
260
|
+
let :statement do
|
261
|
+
double(:statement)
|
262
|
+
end
|
263
|
+
|
264
|
+
let :request do
|
265
|
+
double(:request, values: ['foo', 3])
|
266
|
+
end
|
267
|
+
|
268
|
+
let :query_result do
|
269
|
+
double(:query_result, paging_state: 'thepagingstate')
|
270
|
+
end
|
271
|
+
|
272
|
+
let :options do
|
273
|
+
{:trace => true, :timeout => 3}
|
274
|
+
end
|
275
|
+
|
276
|
+
include_examples 'asynchronous_paged_query_result'
|
277
|
+
|
278
|
+
describe '#next_page' do
|
279
|
+
let :next_query_result do
|
280
|
+
double(:next_query_result, paging_state: 'thenextpagingstate')
|
281
|
+
end
|
282
|
+
|
283
|
+
before do
|
284
|
+
statement.stub(:execute).and_return(Future.resolved(next_query_result))
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'calls the statement and passes the paging state' do
|
288
|
+
paged_query_result.next_page.value
|
289
|
+
statement.should have_received(:execute).with(anything, anything, hash_including(paging_state: 'thepagingstate'))
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'calls the statement and passes the options' do
|
293
|
+
paged_query_result.next_page.value
|
294
|
+
statement.should have_received(:execute).with(anything, anything, hash_including(options))
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'calls the statement and passes the bound values' do
|
298
|
+
paged_query_result.next_page.value
|
299
|
+
statement.should have_received(:execute).with('foo', 3, anything)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'handles the case when there are no bound values' do
|
303
|
+
request.stub(:values).and_return(nil)
|
304
|
+
paged_query_result.next_page.value
|
305
|
+
statement.should have_received(:execute).with(an_instance_of(Hash))
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'returns the result of the call' do
|
309
|
+
f = paged_query_result.next_page
|
310
|
+
f.value.should equal(next_query_result)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe SynchronousPagedQueryResult do
|
316
|
+
let :paged_query_result do
|
317
|
+
described_class.new(asynchronous_paged_query_result)
|
318
|
+
end
|
319
|
+
|
320
|
+
let :asynchronous_paged_query_result do
|
321
|
+
double(:asynchronous_paged_query_result)
|
322
|
+
end
|
323
|
+
|
324
|
+
describe '#next_page' do
|
325
|
+
let :next_query_result do
|
326
|
+
double(:next_query_result)
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'delegates to the wrapped query result and wraps the result in an instance of itself' do
|
330
|
+
next_query_result.stub(:next_page).and_return(Future.resolved(next_query_result))
|
331
|
+
asynchronous_paged_query_result.stub(:next_page).and_return(Future.resolved(next_query_result))
|
332
|
+
second_page = paged_query_result.next_page
|
333
|
+
second_page.next_page
|
334
|
+
next_query_result.should have_received(:next_page)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe '#last_page?' do
|
339
|
+
it 'delegates to the wrapped query result' do
|
340
|
+
asynchronous_paged_query_result.stub(:last_page?).and_return(true)
|
341
|
+
paged_query_result.should be_last_page
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe '#async' do
|
346
|
+
it 'returns the asynchronous results' do
|
347
|
+
paged_query_result.async.should equal(asynchronous_paged_query_result)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|