cql-rb 1.1.3 → 1.2.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -11
  3. data/lib/cql.rb +1 -0
  4. data/lib/cql/client.rb +41 -9
  5. data/lib/cql/client/asynchronous_client.rb +9 -4
  6. data/lib/cql/client/asynchronous_prepared_statement.rb +2 -2
  7. data/lib/cql/client/connection_helper.rb +43 -20
  8. data/lib/cql/client/execute_options_decoder.rb +4 -1
  9. data/lib/cql/client/query_result.rb +7 -3
  10. data/lib/cql/client/query_trace.rb +46 -0
  11. data/lib/cql/client/request_runner.rb +7 -2
  12. data/lib/cql/client/void_result.rb +42 -0
  13. data/lib/cql/compression.rb +53 -0
  14. data/lib/cql/compression/snappy_compressor.rb +42 -0
  15. data/lib/cql/io/io_reactor.rb +9 -4
  16. data/lib/cql/protocol.rb +5 -3
  17. data/lib/cql/protocol/cql_protocol_handler.rb +14 -9
  18. data/lib/cql/protocol/frame_decoder.rb +106 -0
  19. data/lib/cql/protocol/frame_encoder.rb +31 -0
  20. data/lib/cql/protocol/request.rb +7 -11
  21. data/lib/cql/protocol/requests/execute_request.rb +2 -2
  22. data/lib/cql/protocol/requests/options_request.rb +4 -0
  23. data/lib/cql/protocol/requests/prepare_request.rb +2 -2
  24. data/lib/cql/protocol/requests/query_request.rb +2 -2
  25. data/lib/cql/protocol/requests/startup_request.rb +12 -5
  26. data/lib/cql/protocol/response.rb +13 -2
  27. data/lib/cql/protocol/responses/authenticate_response.rb +5 -1
  28. data/lib/cql/protocol/responses/detailed_error_response.rb +2 -2
  29. data/lib/cql/protocol/responses/error_response.rb +7 -2
  30. data/lib/cql/protocol/responses/event_response.rb +4 -2
  31. data/lib/cql/protocol/responses/prepared_result_response.rb +20 -4
  32. data/lib/cql/protocol/responses/ready_response.rb +5 -1
  33. data/lib/cql/protocol/responses/result_response.rb +10 -2
  34. data/lib/cql/protocol/responses/rows_result_response.rb +5 -4
  35. data/lib/cql/protocol/responses/schema_change_event_response.rb +1 -1
  36. data/lib/cql/protocol/responses/schema_change_result_response.rb +5 -4
  37. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +4 -3
  38. data/lib/cql/protocol/responses/{status_change_event_result_response.rb → status_change_event_response.rb} +1 -1
  39. data/lib/cql/protocol/responses/supported_response.rb +5 -1
  40. data/lib/cql/protocol/responses/{topology_change_event_result_response.rb → topology_change_event_response.rb} +0 -0
  41. data/lib/cql/protocol/responses/void_result_response.rb +2 -2
  42. data/lib/cql/version.rb +1 -1
  43. data/spec/cql/client/asynchronous_client_spec.rb +52 -31
  44. data/spec/cql/client/asynchronous_prepared_statement_spec.rb +16 -2
  45. data/spec/cql/client/connection_helper_spec.rb +90 -12
  46. data/spec/cql/client/query_trace_spec.rb +138 -0
  47. data/spec/cql/client/request_runner_spec.rb +44 -7
  48. data/spec/cql/client/void_result_spec.rb +43 -0
  49. data/spec/cql/compression/compression_common.rb +59 -0
  50. data/spec/cql/compression/snappy_compressor_spec.rb +23 -0
  51. data/spec/cql/io/io_reactor_spec.rb +8 -1
  52. data/spec/cql/protocol/cql_protocol_handler_spec.rb +40 -0
  53. data/spec/cql/protocol/frame_decoder_spec.rb +132 -0
  54. data/spec/cql/protocol/frame_encoder_spec.rb +105 -0
  55. data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -4
  56. data/spec/cql/protocol/requests/execute_request_spec.rb +5 -5
  57. data/spec/cql/protocol/requests/options_request_spec.rb +10 -4
  58. data/spec/cql/protocol/requests/prepare_request_spec.rb +3 -3
  59. data/spec/cql/protocol/requests/query_request_spec.rb +10 -5
  60. data/spec/cql/protocol/requests/register_request_spec.rb +3 -3
  61. data/spec/cql/protocol/requests/startup_request_spec.rb +11 -5
  62. data/spec/cql/protocol/responses/authenticate_response_spec.rb +27 -0
  63. data/spec/cql/protocol/responses/detailed_error_response_spec.rb +78 -0
  64. data/spec/cql/protocol/responses/error_response_spec.rb +36 -0
  65. data/spec/cql/protocol/responses/event_response_spec.rb +40 -0
  66. data/spec/cql/protocol/responses/prepared_result_response_spec.rb +108 -0
  67. data/spec/cql/protocol/responses/ready_response_spec.rb +39 -0
  68. data/spec/cql/protocol/responses/result_response_spec.rb +57 -0
  69. data/spec/cql/protocol/responses/rows_result_response_spec.rb +273 -0
  70. data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +93 -0
  71. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +51 -19
  72. data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +34 -0
  73. data/spec/cql/protocol/responses/status_change_event_response_spec.rb +35 -0
  74. data/spec/cql/protocol/responses/supported_response_spec.rb +27 -0
  75. data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +35 -0
  76. data/spec/cql/protocol/responses/void_result_response_spec.rb +29 -0
  77. data/spec/integration/client_spec.rb +45 -0
  78. data/spec/integration/protocol_spec.rb +46 -0
  79. data/spec/spec_helper.rb +2 -1
  80. data/spec/support/fake_io_reactor.rb +1 -1
  81. metadata +51 -10
  82. data/lib/cql/protocol/response_frame.rb +0 -129
  83. data/spec/cql/protocol/request_spec.rb +0 -45
  84. data/spec/cql/protocol/response_frame_spec.rb +0 -811
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77764255905873f7b923f9fca746dbef0496eb15
4
- data.tar.gz: c1c39af44330064cb4d9dd2693d81384dc69f09f
3
+ metadata.gz: 5c27b19f205bb59c5f8fe37faa6259064d85c761
4
+ data.tar.gz: 74615d268c49624381e8c8088fb173834e3c0313
5
5
  SHA512:
6
- metadata.gz: 14452316f397f8f2bdc37f764aaf7c070625be977c6b579c4eb881d3e9736a33eb720da296f370c7dc27de7d4fe1917f192267f1a884ae3381afd870378edbd7
7
- data.tar.gz: fa4f95a86ab0ae162ccc64c9eaed8f3c99c7bc7cf217750617e3339cfba62d31badc1609f63ffc65026818777f9bc69bacdcaa21f88d32d07b730c7f5f007ef2
6
+ metadata.gz: 7e8bd6f3e31b0b6e201baca992267b12502e5b78b71ef64378d4f52b791a8a2036c049650c5c4e7f17a0a1b4814d942a423c802742e5173071430d59d1b811ab
7
+ data.tar.gz: 86539fa464d45531f30aea8198d70a726d20d6bf3247d2b25fe76d1e49a37b568c465772059af4adfd637a7371406f7410389ae824d592cd6b18c43bafcfff56
data/README.md CHANGED
@@ -162,6 +162,19 @@ The default consistency level unless you've set it yourself is `:quorum`.
162
162
 
163
163
  Consistency is ignored for `USE`, `TRUNCATE`, `CREATE` and `ALTER` statements, and some (like `:any`) aren't allowed in all situations.
164
164
 
165
+ ## Compression
166
+
167
+ The CQL protocol supports frame compression, which can give you a performance boost if your requests or responses are big. To enable it you can pass a compressor object when you connect.
168
+
169
+ Cassandra currently supports two compression algorithms: Snappy and LZ4. Support for Snappy compression ships with cql-rb, but in order to use it you will have to install the [snappy](http://rubygems.org/gems/snappy) gem separately. Once it's installed you can enable compression like this:
170
+
171
+ ```ruby
172
+ require 'cql/compression/snappy_compressor'
173
+
174
+ compressor = Cql::Compression::SnappyCompressor.new
175
+ client = Cql::Client.connect(hosts: %w[localhost], compressor: compressor)
176
+ ```
177
+
165
178
  # CQL3
166
179
 
167
180
  This is just a driver for the Cassandra native CQL protocol, it doesn't really know anything about CQL. You can run any CQL3 statement and the driver will return whatever Cassandra replies with.
@@ -206,6 +219,10 @@ end
206
219
 
207
220
  If your process does not fork and you still encounter deadlock errors, it might also be a bug. All IO is done is a dedicated thread, and if something happens that makes that thread shut down, Ruby will detect that the locks that the client code is waiting on can't be unlocked.
208
221
 
222
+ ## I get "Bad file descriptor"
223
+
224
+ If you're using cql-rb on Windows there's an [experimental branch with Windows support](https://github.com/iconara/cql-rb/tree/windows_support). The problem is that Windows does not support non blocking reads on IO objects other than sockets, and the fix is very small. Unfortunately I have no way of properly testing things in Windows, so therefore the "experimental" label.
225
+
209
226
  ## I'm not getting all elements back from my list/set/map
210
227
 
211
228
  There's a known issue with collections that get too big. The protocol uses a short for the size of collections, but there is no way for Cassandra to stop you from creating a collection bigger than 65536 elements, so when you do the size field overflows with strange results. The data is there, you just can't get it back.
@@ -232,9 +249,8 @@ Prereleases will be stable, in the sense that they will have finished and proper
232
249
 
233
250
  # Known bugs & limitations
234
251
 
235
- * No support for compression.
236
- * No support for request tracing.
237
252
  * JRuby 1.6 is not officially supported, although 1.6.8 should work, if you're stuck in JRuby 1.6.8 try and see if it works for you.
253
+ * Windows is not supported (there is experimental support in the [`windows` branch](https://github.com/iconara/cql-rb/tree/windows_support)).
238
254
  * Large results are buffered in memory until the whole response has been loaded, the protocol makes it possible to start to deliver rows to the client code as soon as the metadata is loaded, but this is not supported yet.
239
255
  * There is no cluster introspection utilities (like the `DESCRIBE` commands in `cqlsh`).
240
256
  * New features in v2 of the protocol are not supported
@@ -243,15 +259,7 @@ Also check out the [issues](https://github.com/iconara/cql-rb/issues) for open b
243
259
 
244
260
  # How to contribute
245
261
 
246
- Fork the repository, make your changes in a topic branch that branches off from the right place in the history (HEAD isn't necessarily always right), make your changes and finally submit a pull request.
247
-
248
- Follow the style of the existing code, make sure that existing tests pass, and that everything new has good test coverage. Put some effort into writing clear and concise commit messages, and write a good pull request description.
249
-
250
- It takes time to understand other people's code, and even more time to understand a patch, so do as much as you can to make the maintainers' work easier. Be prepared for rejection, many times a feature is already planned, or the proposed design would be in the way of other planned features, or the maintainers' just feel that it will be faster to implement the features themselves than to try to integrate your patch.
251
-
252
- Feel free to open a pull request before the feature is finished, that way you can have a conversation with the maintainers' during the development, and you can make adjustments to the design as you go along instead of having your whole feature rejected because of reasons such as those above. If you do, please make it clear that the pull request is a work in progress, or a request for comment.
253
-
254
- Always remember that the maintainers' work on this project in their free time and that they don't work for you, or for your benefit. They have no obligation to do what you think is right -- but if you're nice they might anyway.
262
+ [See CONTRIBUTING.md](CONTRIBUTING.md)
255
263
 
256
264
  # Copyright
257
265
 
data/lib/cql.rb CHANGED
@@ -9,5 +9,6 @@ require 'cql/time_uuid'
9
9
  require 'cql/byte_buffer'
10
10
  require 'cql/future'
11
11
  require 'cql/io'
12
+ require 'cql/compression'
12
13
  require 'cql/protocol'
13
14
  require 'cql/client'
data/lib/cql/client.rb CHANGED
@@ -6,12 +6,13 @@ module Cql
6
6
  # if any. `message` contains the human readable error message sent by the
7
7
  # server.
8
8
  class QueryError < CqlError
9
- attr_reader :code, :cql
9
+ attr_reader :code, :cql, :details
10
10
 
11
- def initialize(code, message, cql=nil)
11
+ def initialize(code, message, cql=nil, details=nil)
12
12
  super(message)
13
13
  @code = code
14
14
  @cql = cql
15
+ @details = details
15
16
  end
16
17
  end
17
18
 
@@ -19,6 +20,7 @@ module Cql
19
20
  TimeoutError = Class.new(CqlError)
20
21
  ClientError = Class.new(CqlError)
21
22
  AuthenticationError = Class.new(ClientError)
23
+ IncompleteTraceError = Class.new(ClientError)
22
24
 
23
25
  # A CQL client manages connections to one or more Cassandra nodes and you use
24
26
  # it run queries, insert and update data.
@@ -88,6 +90,11 @@ module Cql
88
90
  # @option options [Integer] :default_consistency (:quorum) The consistency
89
91
  # to use unless otherwise specified. Consistency can also be specified on
90
92
  # a per-request basis.
93
+ # @option options [Cql::Compression::Compressor] :compressor An object that
94
+ # can compress and decompress frames. By specifying this option frame
95
+ # compression will be enabled. If the server does not support compression
96
+ # or the specific compression algorithm specified by the compressor,
97
+ # compression will not be enabled and a warning will be logged.
91
98
  # @option options [Integer] :logger If you want the client to log
92
99
  # significant events pass an object implementing the standard Ruby logger
93
100
  # interface (e.g. quacks like `Logger` from the standard library) with
@@ -142,7 +149,23 @@ module Cql
142
149
 
143
150
  # @!method execute(cql, options_or_consistency=nil)
144
151
  #
145
- # Execute a CQL statement
152
+ # Execute a CQL statement.
153
+ #
154
+ # @example A simple CQL query
155
+ # result = client.execute("SELECT * FROM users WHERE user_name = 'sue'")
156
+ # result.each do |row|
157
+ # p row
158
+ # end
159
+ #
160
+ # @example Specifying the consistency as a symbol
161
+ # client.execute("UPDATE users SET full_name = 'Sue S. Smith' WHERE user_name = 'sue'", consistency: :one)
162
+ #
163
+ # @example Specifying the consistency and other options
164
+ # client.execute("SELECT * FROM users", consistency: :all, timeout: 1.5)
165
+ #
166
+ # @example Activating tracing for a query
167
+ # result = client.execute("SELECT * FROM users", tracing: true)
168
+ # p result.trace_id
146
169
  #
147
170
  # @param [String] cql
148
171
  # @param [Hash] options_or_consistency Either a consistency as a symbol
@@ -153,14 +176,19 @@ module Cql
153
176
  # @option options_or_consistency [Symbol] :timeout (nil) How long to wait
154
177
  # for a response. If this timeout expires a {Cql::TimeoutError} will
155
178
  # be raised.
179
+ # @option options_or_consistency [Symbol] :trace (false) Request tracing
180
+ # for this request. See {Cql::Client::QueryResult} and
181
+ # {Cql::Client::VoidResult} for how to retrieve the tracing data.
156
182
  # @raise [Cql::NotConnectedError] raised when the client is not connected
157
183
  # @raise [Cql::TimeoutError] raised when a timeout was specified and no
158
184
  # response was received within the timeout.
159
185
  # @raise [Cql::QueryError] raised when the CQL has syntax errors or for
160
186
  # other situations when the server complains.
161
- # @return [nil, Cql::Client::QueryResult] Most queries have no result and
162
- # return `nil`, but `SELECT` statements return an `Enumerable` of rows
163
- # (see {Cql::Client::QueryResult}).
187
+ # @return [nil, Cql::Client::QueryResult, Cql::Client::VoidResult] Some
188
+ # queries have no result and return `nil`, but `SELECT` statements
189
+ # return an `Enumerable` of rows (see {Cql::Client::QueryResult}), and
190
+ # `INSERT` and `UPDATE` return a similar type
191
+ # (see {Cql::Client::VoidResult}).
164
192
 
165
193
  # @!method prepare(cql)
166
194
  #
@@ -206,9 +234,11 @@ module Cql
206
234
  # @raise [Cql::Io::IoError] raised when there is an IO error, for example
207
235
  # if the server suddenly closes the connection
208
236
  # @raise [Cql::QueryError] raised when there is an error on the server side
209
- # @return [nil, Cql::Client::QueryResult] Most statements have no result
210
- # and return `nil`, but `SELECT` statements return an `Enumerable` of
211
- # rows (see {Cql::Client::QueryResult}).
237
+ # @return [nil, Cql::Client::QueryResult, Cql::Client::VoidResult] Some
238
+ # queries have no result and return `nil`, but `SELECT` statements
239
+ # return an `Enumerable` of rows (see {Cql::Client::QueryResult}), and
240
+ # `INSERT` and `UPDATE` return a similar type
241
+ # (see {Cql::Client::VoidResult}).
212
242
  def execute(*args)
213
243
  end
214
244
  end
@@ -221,6 +251,8 @@ require 'cql/client/null_logger'
221
251
  require 'cql/client/column_metadata'
222
252
  require 'cql/client/result_metadata'
223
253
  require 'cql/client/query_result'
254
+ require 'cql/client/void_result'
255
+ require 'cql/client/query_trace'
224
256
  require 'cql/client/execute_options_decoder'
225
257
  require 'cql/client/keyspace_changer'
226
258
  require 'cql/client/asynchronous_client'
@@ -5,8 +5,9 @@ module Cql
5
5
  # @private
6
6
  class AsynchronousClient < Client
7
7
  def initialize(options={})
8
+ compressor = options[:compressor]
8
9
  @logger = options[:logger] || NullLogger.new
9
- @io_reactor = options[:io_reactor] || Io::IoReactor.new(Protocol::CqlProtocolHandler)
10
+ @io_reactor = options[:io_reactor] || Io::IoReactor.new(protocol_handler_factory(compressor))
10
11
  @hosts = extract_hosts(options)
11
12
  @initial_keyspace = options[:keyspace]
12
13
  @lock = Mutex.new
@@ -22,7 +23,7 @@ module Cql
22
23
  connection_timeout = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
23
24
  default_consistency = options[:default_consistency] || DEFAULT_CONSISTENCY
24
25
  @execute_options_decoder = ExecuteOptionsDecoder.new(default_consistency)
25
- @connection_helper = ConnectionHelper.new(@io_reactor, port, credentials, connections_per_node, connection_timeout, @logger)
26
+ @connection_helper = ConnectionHelper.new(@io_reactor, port, credentials, connections_per_node, connection_timeout, compressor, @logger)
26
27
  end
27
28
 
28
29
  def connect
@@ -85,8 +86,8 @@ module Cql
85
86
 
86
87
  def execute(cql, options_or_consistency=nil)
87
88
  with_failure_handler do
88
- consistency, timeout = @execute_options_decoder.decode_options(options_or_consistency)
89
- execute_request(Protocol::QueryRequest.new(cql, consistency), timeout)
89
+ consistency, timeout, trace = @execute_options_decoder.decode_options(options_or_consistency)
90
+ execute_request(Protocol::QueryRequest.new(cql, consistency, trace), timeout)
90
91
  end
91
92
  end
92
93
 
@@ -103,6 +104,10 @@ module Cql
103
104
  DEFAULT_CONNECTION_TIMEOUT = 10
104
105
  MAX_RECONNECTION_ATTEMPTS = 5
105
106
 
107
+ def protocol_handler_factory(compressor)
108
+ lambda { |connection, timeout| Protocol::CqlProtocolHandler.new(connection, timeout, compressor) }
109
+ end
110
+
106
111
  def extract_hosts(options)
107
112
  if options[:hosts]
108
113
  options[:hosts].uniq
@@ -60,9 +60,9 @@ module Cql
60
60
  unless bound_args.size == @raw_metadata.size && args.size <= 1
61
61
  raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
62
62
  end
63
- consistency, timeout = @execute_options_decoder.decode_options(args.last)
63
+ consistency, timeout, trace = @execute_options_decoder.decode_options(args.last)
64
64
  statement_id = connection[self]
65
- request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, consistency)
65
+ request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, consistency, trace)
66
66
  @request_runner.execute(connection, request, timeout)
67
67
  end
68
68
  end
@@ -4,7 +4,7 @@ module Cql
4
4
  module Client
5
5
  # @private
6
6
  class ConnectionHelper
7
- def initialize(io_reactor, port, credentials, connections_per_node, connection_timeout, logger)
7
+ def initialize(io_reactor, port, credentials, connections_per_node, connection_timeout, compressor, logger)
8
8
  @io_reactor = io_reactor
9
9
  @port = port
10
10
  @credentials = credentials
@@ -13,6 +13,7 @@ module Cql
13
13
  @logger = logger
14
14
  @request_runner = RequestRunner.new
15
15
  @keyspace_changer = KeyspaceChanger.new
16
+ @compressor = compressor
16
17
  end
17
18
 
18
19
  def connect(hosts, initial_keyspace)
@@ -100,18 +101,50 @@ module Cql
100
101
  end
101
102
 
102
103
  def connect_to_host(host, keyspace)
103
- @logger.debug('Connecting to node at %s:%d' % [host, @port])
104
+ if @compressor
105
+ @logger.debug('Connecting to node at %s:%d using "%s" compression' % [host, @port, @compressor.algorithm])
106
+ else
107
+ @logger.debug('Connecting to node at %s:%d' % [host, @port])
108
+ end
104
109
  connected = @io_reactor.connect(host, @port, @connection_timeout)
105
110
  connected.flat_map do |connection|
106
- initialize_connection(connection, keyspace)
111
+ f = cache_supported_options(connection)
112
+ f = f.flat_map { send_startup_request(connection) }
113
+ f = f.flat_map { |response| maybe_authenticate(response, connection) }
114
+ f = f.flat_map { identify_node(connection) }
115
+ f = f.flat_map { change_keyspace(keyspace, connection) }
116
+ f
107
117
  end
108
118
  end
109
119
 
110
- def initialize_connection(connection, keyspace)
111
- started = @request_runner.execute(connection, Protocol::StartupRequest.new)
112
- authenticated = started.flat_map { |response| maybe_authenticate(response, connection) }
113
- identified = authenticated.flat_map { identify_node(connection) }
114
- identified.flat_map { @keyspace_changer.use_keyspace(keyspace, connection) }
120
+ def cache_supported_options(connection)
121
+ f = @request_runner.execute(connection, Protocol::OptionsRequest.new)
122
+ f.on_value do |supported_options|
123
+ connection[:cql_version] = supported_options['CQL_VERSION']
124
+ connection[:compression] = supported_options['COMPRESSION']
125
+ end
126
+ f
127
+ end
128
+
129
+ def send_startup_request(connection)
130
+ compression = @compressor && @compressor.algorithm
131
+ if @compressor && !connection[:compression].include?(@compressor.algorithm)
132
+ @logger.warn(%[Compression algorithm "#{@compressor.algorithm}" not supported (server supports "#{connection[:compression].join('", "')}")])
133
+ compression = nil
134
+ end
135
+ request = Protocol::StartupRequest.new(nil, compression)
136
+ @request_runner.execute(connection, request)
137
+ end
138
+
139
+ def maybe_authenticate(response, connection)
140
+ return Future.resolved(connection) unless response.is_a?(AuthenticationRequired)
141
+ return Future.failed(AuthenticationError.new('Server requested authentication, but no credentials given')) unless @credentials
142
+ send_credentials(@credentials, connection)
143
+ end
144
+
145
+ def send_credentials(credentials, connection)
146
+ credentials_request = Protocol::CredentialsRequest.new(credentials)
147
+ @request_runner.execute(connection, credentials_request)
115
148
  end
116
149
 
117
150
  def identify_node(connection)
@@ -126,18 +159,8 @@ module Cql
126
159
  f
127
160
  end
128
161
 
129
- def maybe_authenticate(response, connection)
130
- case response
131
- when AuthenticationRequired
132
- if @credentials
133
- credentials_request = Protocol::CredentialsRequest.new(@credentials)
134
- @request_runner.execute(connection, credentials_request).map { connection }
135
- else
136
- Future.failed(AuthenticationError.new('Server requested authentication, but no credentials given'))
137
- end
138
- else
139
- Future.resolved(connection)
140
- end
162
+ def change_keyspace(keyspace, connection)
163
+ @keyspace_changer.use_keyspace(keyspace, connection)
141
164
  end
142
165
 
143
166
  class FailedConnection
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Cql
4
4
  module Client
5
+ # @private
5
6
  class ExecuteOptionsDecoder
6
7
  def initialize(default_consistency)
7
8
  @default_consistency = default_consistency
@@ -10,14 +11,16 @@ module Cql
10
11
  def decode_options(options_or_consistency)
11
12
  consistency = @default_consistency
12
13
  timeout = nil
14
+ trace = false
13
15
  case options_or_consistency
14
16
  when Symbol
15
17
  consistency = options_or_consistency
16
18
  when Hash
17
19
  consistency = options_or_consistency[:consistency] || consistency
18
20
  timeout = options_or_consistency[:timeout]
21
+ trace = options_or_consistency[:trace]
19
22
  end
20
- return consistency, timeout
23
+ return consistency, timeout, trace
21
24
  end
22
25
  end
23
26
  end
@@ -8,14 +8,19 @@ module Cql
8
8
  # @return [ResultMetadata]
9
9
  attr_reader :metadata
10
10
 
11
+ # The ID of the query trace associated with the query, if any.
12
+ #
13
+ # @return [Cql::Uuid]
14
+ attr_reader :trace_id
15
+
11
16
  # @private
12
- def initialize(metadata, rows)
17
+ def initialize(metadata, rows, trace_id)
13
18
  @metadata = ResultMetadata.new(metadata)
14
19
  @rows = rows
20
+ @trace_id = trace_id
15
21
  end
16
22
 
17
23
  # Returns whether or not there are any rows in this result set
18
- #
19
24
  def empty?
20
25
  @rows.empty?
21
26
  end
@@ -24,7 +29,6 @@ module Cql
24
29
  #
25
30
  # @yieldparam [Hash] row each row in the result set as a hash
26
31
  # @return [Enumerable<Hash>]
27
- #
28
32
  def each(&block)
29
33
  @rows.each(&block)
30
34
  end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Client
5
+ # @private
6
+ class QueryTrace
7
+ attr_reader :coordinator, :cql, :started_at, :duration, :events
8
+
9
+ # @private
10
+ def initialize(session, events)
11
+ if session
12
+ raise IncompleteTraceError, 'Trace incomplete, try loading it again' unless session['duration']
13
+ @coordinator = session['coordinator']
14
+ @cql = (parameters = session['parameters']) && parameters['query']
15
+ @started_at = session['started_at']
16
+ @duration = session['duration']/1_000_000.0
17
+ if events
18
+ @events = events.map { |e| TraceEvent.new(e) }.freeze
19
+ end
20
+ else
21
+ @events = [].freeze
22
+ end
23
+ end
24
+ end
25
+
26
+ # @private
27
+ class TraceEvent
28
+ attr_reader :activity, :source, :source_elapsed, :time
29
+
30
+ # @private
31
+ def initialize(event)
32
+ @activity = event['activity']
33
+ @source = event['source']
34
+ @source_elapsed = event['source_elapsed']/1_000_000.0
35
+ @time = event['event_id'].to_time
36
+ end
37
+ end
38
+
39
+ # @private
40
+ class NullQueryTrace < QueryTrace
41
+ def initialize
42
+ super(nil, nil)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -8,14 +8,19 @@ module Cql
8
8
  connection.send_request(request, timeout).map do |response|
9
9
  case response
10
10
  when Protocol::RowsResultResponse
11
- QueryResult.new(response.metadata, response.rows)
11
+ QueryResult.new(response.metadata, response.rows, response.trace_id)
12
+ when Protocol::VoidResultResponse
13
+ response.trace_id ? VoidResult.new(response.trace_id) : VoidResult::INSTANCE
12
14
  when Protocol::ErrorResponse
13
15
  cql = request.is_a?(Protocol::QueryRequest) ? request.cql : nil
14
- raise QueryError.new(response.code, response.message, cql)
16
+ details = response.respond_to?(:details) ? response.details : nil
17
+ raise QueryError.new(response.code, response.message, cql, details)
15
18
  when Protocol::SetKeyspaceResultResponse
16
19
  KeyspaceChanged.new(response.keyspace)
17
20
  when Protocol::AuthenticateResponse
18
21
  AuthenticationRequired.new(response.authentication_class)
22
+ when Protocol::SupportedResponse
23
+ response.options
19
24
  else
20
25
  if block_given?
21
26
  yield response