cql-rb 1.2.2 → 2.0.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +4 -0
  3. data/README.md +139 -17
  4. data/lib/cql/client.rb +237 -8
  5. data/lib/cql/client/asynchronous_client.rb +138 -54
  6. data/lib/cql/client/asynchronous_prepared_statement.rb +41 -6
  7. data/lib/cql/client/authenticators.rb +46 -0
  8. data/lib/cql/client/batch.rb +115 -0
  9. data/lib/cql/client/connector.rb +255 -0
  10. data/lib/cql/client/execute_options_decoder.rb +25 -9
  11. data/lib/cql/client/keyspace_changer.rb +5 -5
  12. data/lib/cql/client/peer_discovery.rb +33 -0
  13. data/lib/cql/client/query_result.rb +124 -1
  14. data/lib/cql/client/request_runner.rb +4 -2
  15. data/lib/cql/client/synchronous_client.rb +14 -2
  16. data/lib/cql/client/synchronous_prepared_statement.rb +19 -1
  17. data/lib/cql/future.rb +97 -50
  18. data/lib/cql/io/connection.rb +0 -1
  19. data/lib/cql/io/io_reactor.rb +1 -1
  20. data/lib/cql/protocol.rb +8 -1
  21. data/lib/cql/protocol/cql_protocol_handler.rb +2 -2
  22. data/lib/cql/protocol/decoding.rb +10 -15
  23. data/lib/cql/protocol/frame_decoder.rb +2 -1
  24. data/lib/cql/protocol/frame_encoder.rb +5 -4
  25. data/lib/cql/protocol/requests/auth_response_request.rb +31 -0
  26. data/lib/cql/protocol/requests/batch_request.rb +59 -0
  27. data/lib/cql/protocol/requests/credentials_request.rb +1 -1
  28. data/lib/cql/protocol/requests/execute_request.rb +45 -17
  29. data/lib/cql/protocol/requests/options_request.rb +1 -1
  30. data/lib/cql/protocol/requests/prepare_request.rb +1 -1
  31. data/lib/cql/protocol/requests/query_request.rb +97 -5
  32. data/lib/cql/protocol/requests/register_request.rb +1 -1
  33. data/lib/cql/protocol/requests/startup_request.rb +4 -4
  34. data/lib/cql/protocol/response.rb +2 -2
  35. data/lib/cql/protocol/responses/auth_challenge_response.rb +25 -0
  36. data/lib/cql/protocol/responses/auth_success_response.rb +25 -0
  37. data/lib/cql/protocol/responses/authenticate_response.rb +1 -1
  38. data/lib/cql/protocol/responses/detailed_error_response.rb +1 -1
  39. data/lib/cql/protocol/responses/error_response.rb +3 -2
  40. data/lib/cql/protocol/responses/event_response.rb +3 -2
  41. data/lib/cql/protocol/responses/prepared_result_response.rb +10 -6
  42. data/lib/cql/protocol/responses/raw_rows_result_response.rb +27 -0
  43. data/lib/cql/protocol/responses/ready_response.rb +1 -1
  44. data/lib/cql/protocol/responses/result_response.rb +2 -2
  45. data/lib/cql/protocol/responses/rows_result_response.rb +43 -23
  46. data/lib/cql/protocol/responses/schema_change_event_response.rb +1 -1
  47. data/lib/cql/protocol/responses/schema_change_result_response.rb +1 -1
  48. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +1 -1
  49. data/lib/cql/protocol/responses/status_change_event_response.rb +1 -1
  50. data/lib/cql/protocol/responses/supported_response.rb +1 -1
  51. data/lib/cql/protocol/responses/void_result_response.rb +1 -1
  52. data/lib/cql/protocol/type_converter.rb +2 -2
  53. data/lib/cql/uuid.rb +2 -2
  54. data/lib/cql/version.rb +1 -1
  55. data/spec/cql/client/asynchronous_client_spec.rb +493 -50
  56. data/spec/cql/client/asynchronous_prepared_statement_spec.rb +193 -11
  57. data/spec/cql/client/authenticators_spec.rb +56 -0
  58. data/spec/cql/client/batch_spec.rb +277 -0
  59. data/spec/cql/client/connector_spec.rb +606 -0
  60. data/spec/cql/client/execute_options_decoder_spec.rb +95 -0
  61. data/spec/cql/client/keyspace_changer_spec.rb +8 -8
  62. data/spec/cql/client/peer_discovery_spec.rb +92 -0
  63. data/spec/cql/client/query_result_spec.rb +352 -0
  64. data/spec/cql/client/request_runner_spec.rb +31 -5
  65. data/spec/cql/client/synchronous_client_spec.rb +44 -1
  66. data/spec/cql/client/synchronous_prepared_statement_spec.rb +63 -1
  67. data/spec/cql/future_spec.rb +50 -2
  68. data/spec/cql/protocol/cql_protocol_handler_spec.rb +16 -5
  69. data/spec/cql/protocol/decoding_spec.rb +16 -6
  70. data/spec/cql/protocol/encoding_spec.rb +3 -1
  71. data/spec/cql/protocol/frame_encoder_spec.rb +99 -50
  72. data/spec/cql/protocol/requests/auth_response_request_spec.rb +62 -0
  73. data/spec/cql/protocol/requests/batch_request_spec.rb +155 -0
  74. data/spec/cql/protocol/requests/credentials_request_spec.rb +1 -1
  75. data/spec/cql/protocol/requests/execute_request_spec.rb +184 -71
  76. data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
  77. data/spec/cql/protocol/requests/prepare_request_spec.rb +1 -1
  78. data/spec/cql/protocol/requests/query_request_spec.rb +255 -32
  79. data/spec/cql/protocol/requests/register_request_spec.rb +1 -1
  80. data/spec/cql/protocol/requests/startup_request_spec.rb +12 -6
  81. data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +31 -0
  82. data/spec/cql/protocol/responses/auth_success_response_spec.rb +31 -0
  83. data/spec/cql/protocol/responses/authenticate_response_spec.rb +2 -1
  84. data/spec/cql/protocol/responses/detailed_error_response_spec.rb +14 -7
  85. data/spec/cql/protocol/responses/error_response_spec.rb +4 -2
  86. data/spec/cql/protocol/responses/event_response_spec.rb +7 -4
  87. data/spec/cql/protocol/responses/prepared_result_response_spec.rb +89 -34
  88. data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +66 -0
  89. data/spec/cql/protocol/responses/ready_response_spec.rb +1 -1
  90. data/spec/cql/protocol/responses/result_response_spec.rb +19 -7
  91. data/spec/cql/protocol/responses/rows_result_response_spec.rb +56 -11
  92. data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +2 -1
  93. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +2 -1
  94. data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +1 -1
  95. data/spec/cql/protocol/responses/status_change_event_response_spec.rb +2 -1
  96. data/spec/cql/protocol/responses/supported_response_spec.rb +2 -1
  97. data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +2 -1
  98. data/spec/cql/protocol/responses/void_result_response_spec.rb +1 -1
  99. data/spec/cql/protocol/type_converter_spec.rb +21 -4
  100. data/spec/cql/uuid_spec.rb +10 -3
  101. data/spec/integration/client_spec.rb +251 -28
  102. data/spec/integration/protocol_spec.rb +213 -62
  103. data/spec/integration/regression_spec.rb +4 -1
  104. data/spec/integration/uuid_spec.rb +4 -1
  105. data/spec/support/fake_io_reactor.rb +5 -5
  106. metadata +36 -7
  107. data/lib/cql/client/connection_helper.rb +0 -181
  108. data/spec/cql/client/connection_helper_spec.rb +0 -429
@@ -5,25 +5,26 @@ module Cql
5
5
  # @private
6
6
  class AsynchronousClient < Client
7
7
  def initialize(options={})
8
- compressor = options[:compressor]
8
+ @compressor = options[:compressor]
9
+ @cql_version = options[:cql_version]
9
10
  @logger = options[:logger] || NullLogger.new
10
- @io_reactor = options[:io_reactor] || Io::IoReactor.new(protocol_handler_factory(compressor))
11
+ @protocol_version = options[:protocol_version] || 2
12
+ @io_reactor = options[:io_reactor] || Io::IoReactor.new(protocol_handler_factory)
11
13
  @hosts = extract_hosts(options)
12
14
  @initial_keyspace = options[:keyspace]
15
+ @connections_per_node = options[:connections_per_node] || 1
13
16
  @lock = Mutex.new
14
- @connected = false
15
- @connecting = false
16
- @closing = false
17
17
  @request_runner = RequestRunner.new
18
18
  @keyspace_changer = KeyspaceChanger.new
19
19
  @connection_manager = ConnectionManager.new
20
- port = options[:port] || DEFAULT_PORT
21
- credentials = options[:credentials]
22
- connections_per_node = options[:connections_per_node] || 1
23
- connection_timeout = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
24
- default_consistency = options[:default_consistency] || DEFAULT_CONSISTENCY
25
- @execute_options_decoder = ExecuteOptionsDecoder.new(default_consistency)
26
- @connection_helper = ConnectionHelper.new(@io_reactor, port, credentials, connections_per_node, connection_timeout, compressor, @logger)
20
+ @execute_options_decoder = ExecuteOptionsDecoder.new(options[:default_consistency] || DEFAULT_CONSISTENCY)
21
+ @port = options[:port] || DEFAULT_PORT
22
+ @connection_timeout = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
23
+ @credentials = options[:credentials]
24
+ @auth_provider = options[:auth_provider] || @credentials && PlainTextAuthProvider.new(*@credentials.values_at(:username, :password))
25
+ @connected = false
26
+ @connecting = false
27
+ @closing = false
27
28
  end
28
29
 
29
30
  def connect
@@ -32,12 +33,15 @@ module Cql
32
33
  return @connected_future if can_execute?
33
34
  @connecting = true
34
35
  @connected_future = begin
35
- f = @connection_helper.connect(@hosts, @initial_keyspace)
36
- f.on_value do |connections|
36
+ f = @io_reactor.start
37
+ f = f.flat_map { connect_with_protocol_version_fallback }
38
+ f = f.flat_map { |connections| connect_to_all_peers(connections) }
39
+ f = f.flat_map do |connections|
37
40
  @connection_manager.add_connections(connections)
38
41
  register_event_listener(@connection_manager.random_connection)
39
42
  end
40
- f.map { self }
43
+ f = f.flat_map { use_keyspace(@connection_manager.snapshot, @initial_keyspace) }
44
+ f.map(self)
41
45
  end
42
46
  end
43
47
  @connected_future.on_complete(&method(:connected))
@@ -49,15 +53,16 @@ module Cql
49
53
  return @closed_future if @closing
50
54
  @closing = true
51
55
  @closed_future = begin
52
- f = @io_reactor.stop
53
56
  if @connecting
54
- ff = @connected_future
55
- ff = f.flat_map { ff }
56
- ff = f.fallback { ff }
57
+ f = @connected_future.recover
58
+ f = f.flat_map { @io_reactor.stop }
59
+ f = f.map(self)
60
+ f
57
61
  else
58
- ff = f
62
+ f = @io_reactor.stop
63
+ f = f.map(self)
64
+ f
59
65
  end
60
- ff.map { self }
61
66
  end
62
67
  end
63
68
  @closed_future.on_complete(&method(:closed))
@@ -74,20 +79,25 @@ module Cql
74
79
 
75
80
  def use(keyspace)
76
81
  with_failure_handler do
77
- connections = @connection_manager.select { |c| c.keyspace != keyspace }
78
- if connections.any?
79
- futures = connections.map { |connection| @keyspace_changer.use_keyspace(keyspace, connection) }
80
- Future.all(*futures).map { nil }
81
- else
82
- Future.resolved
83
- end
82
+ connections = @connection_manager.reject { |c| c.keyspace == keyspace }
83
+ return Future.resolved if connections.empty?
84
+ use_keyspace(connections, keyspace).map(nil)
84
85
  end
85
86
  end
86
87
 
87
- def execute(cql, options_or_consistency=nil)
88
+ def execute(cql, *args)
88
89
  with_failure_handler do
89
- consistency, timeout, trace = @execute_options_decoder.decode_options(options_or_consistency)
90
- execute_request(Protocol::QueryRequest.new(cql, consistency, trace), timeout)
90
+ options_or_consistency = nil
91
+ if args.last.is_a?(Symbol) || args.last.is_a?(Hash)
92
+ options_or_consistency = args.pop
93
+ end
94
+ options = @execute_options_decoder.decode_options(options_or_consistency)
95
+ request = Protocol::QueryRequest.new(cql, args, options[:type_hints], options[:consistency], options[:serial_consistency], options[:page_size], options[:paging_state], options[:trace])
96
+ f = execute_request(request, options[:timeout])
97
+ if options.include?(:page_size)
98
+ f = f.map { |result| AsynchronousQueryPagedQueryResult.new(self, request, result, options) }
99
+ end
100
+ f
91
101
  end
92
102
  end
93
103
 
@@ -97,15 +107,32 @@ module Cql
97
107
  end
98
108
  end
99
109
 
110
+ def batch(type=:logged, options=nil)
111
+ if type.is_a?(Hash)
112
+ options = type
113
+ type = :logged
114
+ end
115
+ b = AsynchronousBatch.new(type, @execute_options_decoder, @connection_manager, options)
116
+ if block_given?
117
+ yield b
118
+ b.execute
119
+ else
120
+ b
121
+ end
122
+ end
123
+
100
124
  private
101
125
 
126
+ DEFAULT_CQL_VERSIONS = {1 => '3.0.0'}
127
+ DEFAULT_CQL_VERSIONS.default = '3.1.0'
128
+ DEFAULT_CQL_VERSIONS.freeze
102
129
  DEFAULT_CONSISTENCY = :quorum
103
130
  DEFAULT_PORT = 9042
104
131
  DEFAULT_CONNECTION_TIMEOUT = 10
105
132
  MAX_RECONNECTION_ATTEMPTS = 5
106
133
 
107
- def protocol_handler_factory(compressor)
108
- lambda { |connection, timeout| Protocol::CqlProtocolHandler.new(connection, timeout, compressor) }
134
+ def protocol_handler_factory
135
+ lambda { |connection, timeout| Protocol::CqlProtocolHandler.new(connection, timeout, @protocol_version, @compressor) }
109
136
  end
110
137
 
111
138
  def extract_hosts(options)
@@ -118,6 +145,52 @@ module Cql
118
145
  end
119
146
  end
120
147
 
148
+ def create_cluster_connector
149
+ cql_version = @cql_version || DEFAULT_CQL_VERSIONS[@protocol_version]
150
+ authentication_step = @protocol_version == 1 ? CredentialsAuthenticationStep.new(@credentials) : SaslAuthenticationStep.new(@auth_provider)
151
+ ClusterConnector.new(
152
+ Connector.new([
153
+ ConnectStep.new(@io_reactor, @port, @connection_timeout, @logger),
154
+ CacheOptionsStep.new,
155
+ InitializeStep.new(cql_version, @compressor, @logger),
156
+ authentication_step,
157
+ CachePropertiesStep.new,
158
+ ]),
159
+ @logger
160
+ )
161
+ end
162
+
163
+ def connect_with_protocol_version_fallback
164
+ f = create_cluster_connector.connect_all(@hosts, @connections_per_node)
165
+ f.fallback do |error|
166
+ if error.is_a?(QueryError) && error.code == 0x0a && @protocol_version > 1
167
+ @logger.warn('Could not connect using protocol version %d (will try again with %d): %s' % [@protocol_version, @protocol_version - 1, error.message])
168
+ @protocol_version -= 1
169
+ connect_with_protocol_version_fallback
170
+ else
171
+ raise error
172
+ end
173
+ end
174
+ end
175
+
176
+ def connect_to_all_peers(seed_connections, initial_keyspace=@initial_keyspace)
177
+ @logger.debug('Looking for additional nodes')
178
+ peer_discovery = PeerDiscovery.new(seed_connections)
179
+ peer_discovery.new_hosts.flat_map do |hosts|
180
+ if hosts.empty?
181
+ @logger.debug('No additional nodes found')
182
+ Future.resolved(seed_connections)
183
+ else
184
+ @logger.debug('%d additional nodes found' % hosts.size)
185
+ f = create_cluster_connector.connect_all(hosts, @connections_per_node)
186
+ f = f.map do |discovered_connections|
187
+ seed_connections + discovered_connections
188
+ end
189
+ f.recover(seed_connections)
190
+ end
191
+ end
192
+ end
193
+
121
194
  def connected(f)
122
195
  if f.resolved?
123
196
  @lock.synchronize do
@@ -163,40 +236,51 @@ module Cql
163
236
  Future.failed(e)
164
237
  end
165
238
 
239
+ def use_keyspace(connections, keyspace)
240
+ futures = connections.map { |connection| @keyspace_changer.use_keyspace(connection, keyspace) }
241
+ Future.all(*futures)
242
+ end
243
+
166
244
  def register_event_listener(connection)
167
245
  register_request = Protocol::RegisterRequest.new(Protocol::TopologyChangeEventResponse::TYPE, Protocol::StatusChangeEventResponse::TYPE)
168
- execute_request(register_request, nil, connection)
169
- connection.on_closed do
170
- if connected?
171
- begin
172
- register_event_listener(@connection_manager.random_connection)
173
- rescue NotConnectedError
174
- # we had started closing down after the connection check
246
+ f = execute_request(register_request, nil, connection)
247
+ f.on_value do
248
+ connection.on_closed do
249
+ if connected?
250
+ begin
251
+ register_event_listener(@connection_manager.random_connection)
252
+ rescue NotConnectedError
253
+ # we had started closing down after the connection check
254
+ end
175
255
  end
176
256
  end
177
- end
178
- connection.on_event do |event|
179
- if event.change == 'UP' || event.change == 'NEW_NODE'
180
- @logger.debug('Received %s event' % event.change)
181
- unless @looking_for_nodes
182
- @looking_for_nodes = true
183
- handle_topology_change.on_complete do |f|
184
- @looking_for_nodes = false
257
+ connection.on_event do |event|
258
+ if event.change == 'UP' || event.change == 'NEW_NODE'
259
+ @logger.debug('Received %s event' % event.change)
260
+ unless @looking_for_nodes
261
+ @looking_for_nodes = true
262
+ handle_topology_change.on_complete do |f|
263
+ @looking_for_nodes = false
264
+ end
185
265
  end
186
266
  end
187
267
  end
188
268
  end
269
+ f
189
270
  end
190
271
 
191
272
  def handle_topology_change(remaning_attempts=MAX_RECONNECTION_ATTEMPTS)
192
273
  with_failure_handler do
193
274
  seed_connections = @connection_manager.snapshot
194
- f = @connection_helper.discover_peers(seed_connections, keyspace)
195
- f.flat_map do |connections|
196
- connected_connections = connections.select(&:connected?)
197
- if connected_connections.any?
198
- @connection_manager.add_connections(connected_connections)
199
- Future.resolved
275
+ f = connect_to_all_peers(seed_connections, keyspace)
276
+ f.flat_map do |all_connections|
277
+ new_connections = all_connections - seed_connections
278
+ if new_connections.size > 0
279
+ f = use_keyspace(new_connections, keyspace)
280
+ f.on_value do
281
+ @connection_manager.add_connections(new_connections)
282
+ end
283
+ f
200
284
  elsif remaning_attempts > 0
201
285
  timeout = 2**(MAX_RECONNECTION_ATTEMPTS - remaning_attempts)
202
286
  @logger.debug('Scheduling new peer discovery in %ds' % timeout)
@@ -18,7 +18,7 @@ module Cql
18
18
  futures = connection_manager.map do |connection|
19
19
  statement.prepare(connection)
20
20
  end
21
- Future.all(*futures).map { statement }
21
+ Future.all(*futures).map(statement)
22
22
  rescue => e
23
23
  Future.failed(e)
24
24
  end
@@ -36,6 +36,21 @@ module Cql
36
36
  Future.failed(e)
37
37
  end
38
38
 
39
+ def batch(type=:logged, options=nil)
40
+ if type.is_a?(Hash)
41
+ options = type
42
+ type = :logged
43
+ end
44
+ b = AsynchronousBatch.new(type, @execute_options_decoder, @connection_manager, options)
45
+ pb = AsynchronousPreparedStatementBatch.new(self, b)
46
+ if block_given?
47
+ yield pb
48
+ pb.execute
49
+ else
50
+ pb
51
+ end
52
+ end
53
+
39
54
  # @private
40
55
  def prepare(connection)
41
56
  prepare_request = Protocol::PrepareRequest.new(@cql)
@@ -46,25 +61,45 @@ module Cql
46
61
  # is that we assign the same data multiple times
47
62
  @raw_metadata = response.metadata
48
63
  @metadata = ResultMetadata.new(@raw_metadata)
64
+ @raw_result_metadata = response.result_metadata
65
+ if @raw_result_metadata
66
+ @result_metadata = ResultMetadata.new(@raw_result_metadata)
67
+ end
49
68
  end
50
69
  hex_id = response.id.each_byte.map { |x| x.to_s(16).rjust(2, '0') }.join('')
51
70
  @logger.debug('Statement %s prepared on node %s (%s:%d)' % [hex_id, connection[:host_id].to_s, connection.host, connection.port])
52
71
  end
53
- f.map { self }
72
+ f.map(self)
73
+ end
74
+
75
+ # @private
76
+ def add_to_batch(batch, connection, bound_args)
77
+ statement_id = connection[self]
78
+ unless statement_id
79
+ raise NotPreparedError
80
+ end
81
+ unless bound_args.size == @raw_metadata.size
82
+ raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
83
+ end
84
+ batch.add_prepared(statement_id, @raw_metadata, bound_args)
54
85
  end
55
86
 
56
87
  private
57
88
 
58
89
  def run(args, connection)
59
- statement_id = connection[self]
60
90
  bound_args = args.shift(@raw_metadata.size)
61
91
  unless bound_args.size == @raw_metadata.size && args.size <= 1
62
92
  raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
63
93
  end
64
- consistency, timeout, trace = @execute_options_decoder.decode_options(args.last)
94
+ options = @execute_options_decoder.decode_options(args.last)
65
95
  statement_id = connection[self]
66
- request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, consistency, trace)
67
- @request_runner.execute(connection, request, timeout)
96
+ request_metadata = @raw_result_metadata.nil?
97
+ request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, request_metadata, options[:consistency], options[:serial_consistency], options[:page_size], options[:paging_state], options[:trace])
98
+ f = @request_runner.execute(connection, request, options[:timeout], @raw_result_metadata)
99
+ if options.include?(:page_size)
100
+ f = f.map { |result| AsynchronousPreparedPagedQueryResult.new(self, request, result, options) }
101
+ end
102
+ f
68
103
  end
69
104
  end
70
105
  end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Client
5
+ # Auth provider used for Cassandra's built in authentication.
6
+ #
7
+ # There is no need to create instances of this class to pass as `:auth_provider`
8
+ # to {Cql::Client.connect}, instead use the `:credentials` option and one
9
+ # will be created automatically for you.
10
+ class PlainTextAuthProvider
11
+ def initialize(username, password)
12
+ @username = username
13
+ @password = password
14
+ end
15
+
16
+ def create_authenticator(authentication_class)
17
+ if authentication_class == PASSWORD_AUTHENTICATOR_FQCN
18
+ PlainTextAuthenticator.new(@username, @password)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ PASSWORD_AUTHENTICATOR_FQCN = 'org.apache.cassandra.auth.PasswordAuthenticator'.freeze
25
+ end
26
+
27
+ # Authenticator used for Cassandra's built in authentication,
28
+ # see {Cql::Client::PlainTextAuthProvider}
29
+ class PlainTextAuthenticator
30
+ def initialize(username, password)
31
+ @username = username
32
+ @password = password
33
+ end
34
+
35
+ def initial_response
36
+ "\x00#{@username}\x00#{@password}"
37
+ end
38
+
39
+ def challenge_response(token)
40
+ end
41
+
42
+ def authentication_successful(token)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Client
5
+ # @private
6
+ class AsynchronousBatch < Batch
7
+ def initialize(type, execute_options_decoder, connection_manager, options=nil)
8
+ raise ArgumentError, "Unknown batch type: #{type}" unless BATCH_TYPES.include?(type)
9
+ @type = type
10
+ @execute_options_decoder = execute_options_decoder
11
+ @connection_manager = connection_manager
12
+ @options = options
13
+ @request_runner = RequestRunner.new
14
+ @parts = []
15
+ end
16
+
17
+ def add(*args)
18
+ @parts << args
19
+ nil
20
+ end
21
+
22
+ def execute(options=nil)
23
+ options = @execute_options_decoder.decode_options(@options, options)
24
+ connection = nil
25
+ attempts = 0
26
+ begin
27
+ connection = @connection_manager.random_connection
28
+ request = Protocol::BatchRequest.new(BATCH_TYPES[@type], options[:consistency], options[:trace])
29
+ @parts.each do |cql_or_statement, *bound_args|
30
+ if cql_or_statement.is_a?(String)
31
+ type_hints = nil
32
+ if bound_args.last.is_a?(Hash) && bound_args.last.include?(:type_hints)
33
+ bound_args = bound_args.dup
34
+ type_hints = bound_args.pop[:type_hints]
35
+ end
36
+ request.add_query(cql_or_statement, bound_args, type_hints)
37
+ else
38
+ cql_or_statement.add_to_batch(request, connection, bound_args)
39
+ end
40
+ end
41
+ rescue NotPreparedError
42
+ attempts += 1
43
+ if attempts < 3
44
+ retry
45
+ else
46
+ raise
47
+ end
48
+ end
49
+ @request_runner.execute(connection, request, options[:timeout])
50
+ end
51
+
52
+ private
53
+
54
+ BATCH_TYPES = {
55
+ :logged => Protocol::BatchRequest::LOGGED_TYPE,
56
+ :unlogged => Protocol::BatchRequest::UNLOGGED_TYPE,
57
+ :counter => Protocol::BatchRequest::COUNTER_TYPE,
58
+ }.freeze
59
+ end
60
+
61
+ # @private
62
+ class SynchronousBatch < Batch
63
+ include SynchronousBacktrace
64
+
65
+ def initialize(asynchronous_batch)
66
+ @asynchronous_batch = asynchronous_batch
67
+ end
68
+
69
+ def async
70
+ @asynchronous_batch
71
+ end
72
+
73
+ def add(*args)
74
+ @asynchronous_batch.add(*args)
75
+ end
76
+
77
+ def execute(options=nil)
78
+ synchronous_backtrace { @asynchronous_batch.execute(options).value }
79
+ end
80
+ end
81
+
82
+ # @private
83
+ class AsynchronousPreparedStatementBatch < PreparedStatementBatch
84
+ def initialize(prepared_statement, batch)
85
+ @prepared_statement = prepared_statement
86
+ @batch = batch
87
+ end
88
+
89
+ def add(*args)
90
+ @batch.add(@prepared_statement, *args)
91
+ end
92
+
93
+ def execute(options=nil)
94
+ @batch.execute(options)
95
+ end
96
+ end
97
+
98
+ # @private
99
+ class SynchronousPreparedStatementBatch < PreparedStatementBatch
100
+ include SynchronousBacktrace
101
+
102
+ def initialize(asynchronous_batch)
103
+ @asynchronous_batch = asynchronous_batch
104
+ end
105
+
106
+ def add(*args)
107
+ @asynchronous_batch.add(*args)
108
+ end
109
+
110
+ def execute(options=nil)
111
+ synchronous_backtrace { @asynchronous_batch.execute(options).value }
112
+ end
113
+ end
114
+ end
115
+ end