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,255 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Cql
|
4
|
+
module Client
|
5
|
+
# @private
|
6
|
+
class ClusterConnector
|
7
|
+
def initialize(sequence, logger)
|
8
|
+
@sequence = sequence
|
9
|
+
@logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect_all(hosts, connections_per_node)
|
13
|
+
connections = hosts.flat_map do |host|
|
14
|
+
Array.new(connections_per_node) do
|
15
|
+
f = @sequence.connect(host)
|
16
|
+
f.on_value { |connection| register_logging(connection) }
|
17
|
+
f.recover do |error|
|
18
|
+
@logger.warn('Failed connecting to node at %s: %s' % [host, error.message])
|
19
|
+
FailedConnection.new(error, host)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
Future.all(*connections).map do |connections|
|
24
|
+
connected_connections = connections.select(&:connected?)
|
25
|
+
if connected_connections.empty?
|
26
|
+
e = connections.first.error
|
27
|
+
if e.is_a?(Cql::QueryError) && e.code == 0x100
|
28
|
+
e = AuthenticationError.new(e.message)
|
29
|
+
end
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
connected_connections
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def register_logging(connection)
|
39
|
+
args = [connection[:host_id], connection.host, connection.port, connection[:data_center]]
|
40
|
+
@logger.info('Connected to node %s at %s:%d in data center %s' % args)
|
41
|
+
connection.on_closed do |cause|
|
42
|
+
message = 'Connection to node %s at %s:%d in data center %s closed' % args
|
43
|
+
if cause
|
44
|
+
message << (' unexpectedly: %s' % cause.message)
|
45
|
+
@logger.warn(message)
|
46
|
+
else
|
47
|
+
@logger.info(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @private
|
54
|
+
class Connector
|
55
|
+
def initialize(steps)
|
56
|
+
@steps = steps.dup
|
57
|
+
end
|
58
|
+
|
59
|
+
def connect(host)
|
60
|
+
pending_connection = PendingConnection.new(host)
|
61
|
+
seed = Future.resolved(pending_connection)
|
62
|
+
f = @steps.reduce(seed) do |chain, step|
|
63
|
+
chain.flat_map do |pending_connection|
|
64
|
+
step.run(pending_connection)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
f.map do |pending_connection|
|
68
|
+
pending_connection.connection
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @private
|
74
|
+
class ConnectStep
|
75
|
+
def initialize(io_reactor, port, connection_timeout, logger)
|
76
|
+
@io_reactor = io_reactor
|
77
|
+
@port = port
|
78
|
+
@connection_timeout = connection_timeout
|
79
|
+
@logger = logger
|
80
|
+
end
|
81
|
+
|
82
|
+
def run(pending_connection)
|
83
|
+
@logger.debug('Connecting to node at %s:%d' % [pending_connection.host, @port])
|
84
|
+
@io_reactor.connect(pending_connection.host, @port, @connection_timeout).map do |connection|
|
85
|
+
pending_connection.with_connection(connection)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# @private
|
91
|
+
class CacheOptionsStep
|
92
|
+
def run(pending_connection)
|
93
|
+
f = pending_connection.execute(Protocol::OptionsRequest.new)
|
94
|
+
f.on_value do |supported_options|
|
95
|
+
pending_connection[:cql_version] = supported_options['CQL_VERSION']
|
96
|
+
pending_connection[:compression] = supported_options['COMPRESSION']
|
97
|
+
end
|
98
|
+
f.map(pending_connection)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @private
|
103
|
+
class InitializeStep
|
104
|
+
def initialize(cql_version, compressor, logger)
|
105
|
+
@cql_version = cql_version
|
106
|
+
@compressor = compressor
|
107
|
+
@logger = logger
|
108
|
+
end
|
109
|
+
|
110
|
+
def run(pending_connection)
|
111
|
+
compression = @compressor && @compressor.algorithm
|
112
|
+
supported_algorithms = pending_connection[:compression]
|
113
|
+
if @compressor && !supported_algorithms.include?(@compressor.algorithm)
|
114
|
+
@logger.warn(%[Compression algorithm "#{@compressor.algorithm}" not supported (server supports "#{supported_algorithms.join('", "')}")])
|
115
|
+
compression = nil
|
116
|
+
elsif @compressor
|
117
|
+
@logger.debug('Using "%s" compression' % @compressor.algorithm)
|
118
|
+
end
|
119
|
+
f = pending_connection.execute(Protocol::StartupRequest.new(@cql_version, compression))
|
120
|
+
f.map do |startup_response|
|
121
|
+
if startup_response.is_a?(AuthenticationRequired)
|
122
|
+
pending_connection.with_authentication_class(startup_response.authentication_class)
|
123
|
+
else
|
124
|
+
pending_connection
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @private
|
131
|
+
class SaslAuthenticationStep
|
132
|
+
def initialize(auth_provider)
|
133
|
+
@auth_provider = auth_provider
|
134
|
+
end
|
135
|
+
|
136
|
+
def run(pending_connection)
|
137
|
+
if pending_connection.authentication_class
|
138
|
+
begin
|
139
|
+
authenticator = @auth_provider && @auth_provider.create_authenticator(pending_connection.authentication_class)
|
140
|
+
if authenticator
|
141
|
+
token = authenticator.initial_response
|
142
|
+
challenge_cycle(pending_connection, authenticator, token)
|
143
|
+
elsif @auth_provider
|
144
|
+
Future.failed(AuthenticationError.new('Auth provider does not support the required authentication class "%s" and/or protocol version %d' % [pending_connection.authentication_class, @protocol_version]))
|
145
|
+
else
|
146
|
+
Future.failed(AuthenticationError.new('Server requested authentication, but no auth provider found'))
|
147
|
+
end
|
148
|
+
rescue => e
|
149
|
+
Future.failed(AuthenticationError.new('Auth provider raised an error: %s' % e.message))
|
150
|
+
end
|
151
|
+
else
|
152
|
+
Future.resolved(pending_connection)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def challenge_cycle(pending_connection, authenticator, response_token)
|
157
|
+
request = Protocol::AuthResponseRequest.new(response_token)
|
158
|
+
f = pending_connection.execute(request) { |raw_response| raw_response }
|
159
|
+
f.flat_map do |response|
|
160
|
+
case response
|
161
|
+
when Protocol::AuthChallengeResponse
|
162
|
+
token = authenticator.challenge_response(response.token)
|
163
|
+
challenge_cycle(pending_connection, authenticator, token)
|
164
|
+
when Protocol::AuthSuccessResponse
|
165
|
+
authenticator.authentication_successful(response.token)
|
166
|
+
Future.resolved(pending_connection)
|
167
|
+
else
|
168
|
+
Future.resolved(pending_connection)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# @private
|
175
|
+
class CredentialsAuthenticationStep
|
176
|
+
def initialize(credentials)
|
177
|
+
@credentials = credentials
|
178
|
+
end
|
179
|
+
|
180
|
+
def run(pending_connection)
|
181
|
+
if pending_connection.authentication_class
|
182
|
+
if @credentials
|
183
|
+
request = Protocol::CredentialsRequest.new(@credentials)
|
184
|
+
pending_connection.execute(request).map(pending_connection)
|
185
|
+
else
|
186
|
+
Future.failed(AuthenticationError.new('Server requested authentication, but no credentials provided'))
|
187
|
+
end
|
188
|
+
else
|
189
|
+
Future.resolved(pending_connection)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# @private
|
195
|
+
class CachePropertiesStep
|
196
|
+
def run(pending_connection)
|
197
|
+
request = Protocol::QueryRequest.new('SELECT data_center, host_id FROM system.local', nil, nil, :one)
|
198
|
+
f = pending_connection.execute(request)
|
199
|
+
f.on_value do |result|
|
200
|
+
unless result.empty?
|
201
|
+
pending_connection[:host_id] = result.first['host_id']
|
202
|
+
pending_connection[:data_center] = result.first['data_center']
|
203
|
+
end
|
204
|
+
end
|
205
|
+
f.map(pending_connection)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# @private
|
210
|
+
class PendingConnection
|
211
|
+
attr_reader :host, :connection, :authentication_class
|
212
|
+
|
213
|
+
def initialize(host, connection=nil, authentication_class=nil)
|
214
|
+
@host = host
|
215
|
+
@connection = connection
|
216
|
+
@authentication_class = authentication_class
|
217
|
+
@request_runner = RequestRunner.new
|
218
|
+
end
|
219
|
+
|
220
|
+
def with_connection(connection)
|
221
|
+
self.class.new(host, connection, @authentication_class)
|
222
|
+
end
|
223
|
+
|
224
|
+
def with_authentication_class(authentication_class)
|
225
|
+
self.class.new(host, @connection, authentication_class)
|
226
|
+
end
|
227
|
+
|
228
|
+
def [](key)
|
229
|
+
@connection[key]
|
230
|
+
end
|
231
|
+
|
232
|
+
def []=(key, value)
|
233
|
+
@connection[key] = value
|
234
|
+
end
|
235
|
+
|
236
|
+
def execute(request, &block)
|
237
|
+
@request_runner.execute(@connection, request, nil, nil, &block)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# @private
|
242
|
+
class FailedConnection
|
243
|
+
attr_reader :error, :host
|
244
|
+
|
245
|
+
def initialize(error, host)
|
246
|
+
@error = error
|
247
|
+
@host = host
|
248
|
+
end
|
249
|
+
|
250
|
+
def connected?
|
251
|
+
false
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -6,21 +6,37 @@ module Cql
|
|
6
6
|
class ExecuteOptionsDecoder
|
7
7
|
def initialize(default_consistency)
|
8
8
|
@default_consistency = default_consistency
|
9
|
+
@default_options = {:consistency => @default_consistency}.freeze
|
9
10
|
end
|
10
11
|
|
11
|
-
def decode_options(
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def decode_options(*args)
|
13
|
+
if args.empty?
|
14
|
+
@default_options
|
15
|
+
elsif args.size == 1
|
16
|
+
decode_one(args.first)
|
17
|
+
else
|
18
|
+
args.each_with_object({}) do |options_or_consistency, result|
|
19
|
+
result.merge!(decode_one(options_or_consistency))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def decode_one(options_or_consistency)
|
27
|
+
return @default_options unless options_or_consistency
|
15
28
|
case options_or_consistency
|
16
29
|
when Symbol
|
17
|
-
consistency
|
30
|
+
{:consistency => options_or_consistency}
|
18
31
|
when Hash
|
19
|
-
|
20
|
-
|
21
|
-
|
32
|
+
if options_or_consistency.include?(:consistency)
|
33
|
+
options_or_consistency
|
34
|
+
else
|
35
|
+
options = options_or_consistency.dup
|
36
|
+
options[:consistency] = @default_consistency
|
37
|
+
options
|
38
|
+
end
|
22
39
|
end
|
23
|
-
return consistency, timeout, trace
|
24
40
|
end
|
25
41
|
end
|
26
42
|
end
|
@@ -6,15 +6,15 @@ module Cql
|
|
6
6
|
class KeyspaceChanger
|
7
7
|
KEYSPACE_NAME_PATTERN = /^\w[\w\d_]*$|^"\w[\w\d_]*"$/
|
8
8
|
|
9
|
-
def initialize
|
10
|
-
@request_runner =
|
9
|
+
def initialize(request_runner=RequestRunner.new)
|
10
|
+
@request_runner = request_runner
|
11
11
|
end
|
12
12
|
|
13
|
-
def use_keyspace(
|
13
|
+
def use_keyspace(connection, keyspace)
|
14
14
|
return Future.resolved(connection) unless keyspace
|
15
15
|
return Future.failed(InvalidKeyspaceNameError.new(%("#{keyspace}" is not a valid keyspace name))) unless valid_keyspace_name?(keyspace)
|
16
|
-
request = Protocol::QueryRequest.new("USE #{keyspace}", :one)
|
17
|
-
@request_runner.execute(connection, request).map
|
16
|
+
request = Protocol::QueryRequest.new("USE #{keyspace}", nil, nil, :one)
|
17
|
+
@request_runner.execute(connection, request).map(connection)
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Cql
|
4
|
+
module Client
|
5
|
+
class PeerDiscovery
|
6
|
+
def initialize(seed_connections)
|
7
|
+
@seed_connections = seed_connections
|
8
|
+
@connection = seed_connections.sample
|
9
|
+
@request_runner = RequestRunner.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_hosts
|
13
|
+
request = Protocol::QueryRequest.new('SELECT peer, data_center, host_id, rpc_address FROM system.peers', nil, nil, :one)
|
14
|
+
response = @request_runner.execute(@connection, request)
|
15
|
+
response.map do |result|
|
16
|
+
result.each_with_object([]) do |row, new_peers|
|
17
|
+
if include?(row['host_id'], row['data_center'])
|
18
|
+
rpc_address = row['rpc_address'].to_s
|
19
|
+
rpc_address = row['peer'].to_s if rpc_address == '0.0.0.0'
|
20
|
+
new_peers << rpc_address
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def include?(host_id, dc)
|
29
|
+
@seed_connections.any? { |c| c[:data_center] == dc } && @seed_connections.none? { |c| c[:host_id] == host_id }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -14,10 +14,14 @@ module Cql
|
|
14
14
|
attr_reader :trace_id
|
15
15
|
|
16
16
|
# @private
|
17
|
-
|
17
|
+
attr_reader :paging_state
|
18
|
+
|
19
|
+
# @private
|
20
|
+
def initialize(metadata, rows, trace_id, paging_state)
|
18
21
|
@metadata = ResultMetadata.new(metadata)
|
19
22
|
@rows = rows
|
20
23
|
@trace_id = trace_id
|
24
|
+
@paging_state = paging_state
|
21
25
|
end
|
22
26
|
|
23
27
|
# Returns whether or not there are any rows in this result set
|
@@ -34,5 +38,124 @@ module Cql
|
|
34
38
|
end
|
35
39
|
alias_method :each_row, :each
|
36
40
|
end
|
41
|
+
|
42
|
+
class PagedQueryResult < QueryResult
|
43
|
+
def metadata
|
44
|
+
@result.metadata
|
45
|
+
end
|
46
|
+
|
47
|
+
def trace_id
|
48
|
+
@result.trace_id
|
49
|
+
end
|
50
|
+
|
51
|
+
def paging_state
|
52
|
+
@result.paging_state
|
53
|
+
end
|
54
|
+
|
55
|
+
def empty?
|
56
|
+
@result.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def each(&block)
|
60
|
+
@result.each(&block)
|
61
|
+
end
|
62
|
+
alias_method :each_row, :each
|
63
|
+
|
64
|
+
def last_page?
|
65
|
+
@last_page
|
66
|
+
end
|
67
|
+
|
68
|
+
def next_page
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @private
|
73
|
+
class AsynchronousPagedQueryResult < PagedQueryResult
|
74
|
+
def initialize(request, result, options)
|
75
|
+
@request = request
|
76
|
+
@result = result
|
77
|
+
@result = result
|
78
|
+
@options = options.merge(paging_state: result.paging_state)
|
79
|
+
@last_page = !result.paging_state
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @private
|
84
|
+
class AsynchronousQueryPagedQueryResult < AsynchronousPagedQueryResult
|
85
|
+
def initialize(client, request, result, options)
|
86
|
+
super(request, result, options)
|
87
|
+
@client = client
|
88
|
+
end
|
89
|
+
|
90
|
+
def next_page
|
91
|
+
@client.execute(@request.cql, *@request.values, @options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# @private
|
96
|
+
class AsynchronousPreparedPagedQueryResult < AsynchronousPagedQueryResult
|
97
|
+
def initialize(prepared_statement, request, result, options)
|
98
|
+
super(request, result, options)
|
99
|
+
@prepared_statement = prepared_statement
|
100
|
+
end
|
101
|
+
|
102
|
+
def next_page
|
103
|
+
@prepared_statement.execute(*@request.values, @options)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @private
|
108
|
+
class SynchronousPagedQueryResult < PagedQueryResult
|
109
|
+
include SynchronousBacktrace
|
110
|
+
|
111
|
+
def initialize(asynchronous_result)
|
112
|
+
@result = asynchronous_result
|
113
|
+
end
|
114
|
+
|
115
|
+
def async
|
116
|
+
@result
|
117
|
+
end
|
118
|
+
|
119
|
+
def last_page?
|
120
|
+
@result.last_page?
|
121
|
+
end
|
122
|
+
|
123
|
+
def next_page
|
124
|
+
synchronous_backtrace { self.class.new(@result.next_page.value) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# @private
|
129
|
+
class LazyQueryResult < QueryResult
|
130
|
+
def initialize(metadata, lazy_rows, trace_id, paging_state)
|
131
|
+
super(metadata, nil, trace_id, paging_state)
|
132
|
+
@raw_metadata = metadata
|
133
|
+
@lazy_rows = lazy_rows
|
134
|
+
@lock = Mutex.new
|
135
|
+
end
|
136
|
+
|
137
|
+
def empty?
|
138
|
+
ensure_materialized
|
139
|
+
super
|
140
|
+
end
|
141
|
+
|
142
|
+
def each(&block)
|
143
|
+
ensure_materialized
|
144
|
+
super
|
145
|
+
end
|
146
|
+
alias_method :each_row, :each
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def ensure_materialized
|
151
|
+
unless @rows
|
152
|
+
@lock.synchronize do
|
153
|
+
unless @rows
|
154
|
+
@rows = @lazy_rows.materialize(@raw_metadata)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
37
160
|
end
|
38
161
|
end
|