cassandra-driver 1.2.0 → 2.0.0

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.
Files changed (57) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +4 -4
  3. data/lib/cassandra.rb +5 -3
  4. data/lib/cassandra/cluster/client.rb +88 -95
  5. data/lib/cassandra/cluster/control_connection.rb +14 -13
  6. data/lib/cassandra/column.rb +1 -9
  7. data/lib/cassandra/execution/options.rb +24 -1
  8. data/lib/cassandra/executors.rb +2 -0
  9. data/lib/cassandra/load_balancing.rb +0 -2
  10. data/lib/cassandra/protocol.rb +7 -5
  11. data/lib/cassandra/protocol/coder.rb +509 -0
  12. data/lib/cassandra/protocol/cql_byte_buffer.rb +4 -0
  13. data/lib/cassandra/protocol/cql_protocol_handler.rb +38 -57
  14. data/lib/cassandra/protocol/requests/auth_response_request.rb +1 -1
  15. data/lib/cassandra/protocol/requests/batch_request.rb +35 -19
  16. data/lib/cassandra/protocol/requests/credentials_request.rb +1 -1
  17. data/lib/cassandra/protocol/requests/execute_request.rb +3 -16
  18. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  19. data/lib/cassandra/protocol/requests/prepare_request.rb +1 -1
  20. data/lib/cassandra/protocol/requests/query_request.rb +5 -61
  21. data/lib/cassandra/protocol/requests/register_request.rb +1 -1
  22. data/lib/cassandra/protocol/requests/startup_request.rb +1 -1
  23. data/lib/cassandra/protocol/response.rb +0 -9
  24. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +40 -0
  25. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +0 -4
  26. data/lib/cassandra/protocol/responses/auth_success_response.rb +1 -5
  27. data/lib/cassandra/protocol/responses/authenticate_response.rb +0 -4
  28. data/lib/cassandra/protocol/responses/error_response.rb +0 -12
  29. data/lib/cassandra/protocol/responses/event_response.rb +0 -8
  30. data/lib/cassandra/protocol/responses/prepared_result_response.rb +0 -10
  31. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
  32. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +42 -0
  33. data/lib/cassandra/protocol/responses/ready_response.rb +0 -4
  34. data/lib/cassandra/protocol/responses/result_response.rb +0 -7
  35. data/lib/cassandra/protocol/responses/rows_result_response.rb +0 -101
  36. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +0 -3
  37. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +0 -4
  38. data/lib/cassandra/protocol/responses/status_change_event_response.rb +0 -4
  39. data/lib/cassandra/protocol/responses/supported_response.rb +0 -4
  40. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +41 -0
  41. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +39 -0
  42. data/lib/cassandra/protocol/responses/void_result_response.rb +0 -4
  43. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +44 -0
  44. data/lib/cassandra/protocol/v1.rb +238 -0
  45. data/lib/cassandra/session.rb +95 -16
  46. data/lib/cassandra/statements/batch.rb +33 -6
  47. data/lib/cassandra/statements/bound.rb +3 -3
  48. data/lib/cassandra/statements/prepared.rb +38 -10
  49. data/lib/cassandra/statements/simple.rb +72 -3
  50. data/lib/cassandra/table.rb +2 -3
  51. data/lib/cassandra/util.rb +18 -0
  52. data/lib/cassandra/version.rb +1 -1
  53. metadata +8 -5
  54. data/lib/cassandra/protocol/frame_decoder.rb +0 -128
  55. data/lib/cassandra/protocol/frame_encoder.rb +0 -48
  56. data/lib/cassandra/protocol/responses/detailed_error_response.rb +0 -75
  57. data/lib/cassandra/protocol/type_converter.rb +0 -389
@@ -55,18 +55,45 @@ module Cassandra
55
55
  @statements = []
56
56
  end
57
57
 
58
- # Adds a statement to this batch
58
+ # @!method add(statement, args)
59
+ # Adds a statement to this batch.
60
+ #
59
61
  # @param statement [String, Cassandra::Statements::Simple,
60
- # Cassandra::Statements::Prepared, Cassandra::Statements::Bound] statement to add
61
- # @param args [*Object] arguments to paramterized query or prepared
62
- # statement
62
+ # Cassandra::Statements::Prepared, Cassandra::Statements::Bound]
63
+ # statement to add.
64
+ # @param args [Array] positional arguments to bind, must contain
65
+ # the same number of parameters as the number of positional (`?`)
66
+ # markers in the original CQL passed to {Cassandra::Session#prepare}
67
+ #
68
+ # @overload add(statement, *args)
69
+ # Adds a statement to this batch using the deprecated splat-style way of
70
+ # passing positional arguments
71
+ #
72
+ # @deprecated Please pass a single {Array} of positional arguments, the
73
+ # `*args` style is deprecated.
74
+ #
75
+ # @param statement [String, Cassandra::Statements::Simple,
76
+ # Cassandra::Statements::Prepared, Cassandra::Statements::Bound]
77
+ # statement to add.
78
+ # @param args [*Object] **this style of positional arguments is
79
+ # deprecated, please pass a single {Array} instead** - arguments to
80
+ # paramterized query or prepared statement
81
+ #
63
82
  # @return [self]
64
83
  def add(statement, *args)
84
+ if args.one? && args.first.is_a?(::Array)
85
+ args = args.first
86
+ elsif !args.empty?
87
+ ::Kernel.warn "[WARNING] Splat style (*args) positional arguments " \
88
+ "are deprecated, pass an Array instead - called " \
89
+ "from #{caller.first}"
90
+ end
91
+
65
92
  case statement
66
93
  when String
67
- @statements << Simple.new(statement, *args)
94
+ @statements << Simple.new(statement, args)
68
95
  when Prepared
69
- @statements << statement.bind(*args)
96
+ @statements << statement.bind(args)
70
97
  when Bound, Simple
71
98
  @statements << statement
72
99
  else
@@ -27,12 +27,12 @@ module Cassandra
27
27
  # @return [Array<Object>] a list of positional parameters for the cql
28
28
  attr_reader :params
29
29
  # @private
30
- attr_reader :params_metadata, :result_metadata, :keyspace, :partition_key
30
+ attr_reader :params_types, :result_metadata, :keyspace, :partition_key
31
31
 
32
32
  # @private
33
- def initialize(cql, params_metadata, result_metadata, params, keyspace = nil, partition_key = nil)
33
+ def initialize(cql, params_types, result_metadata, params, keyspace = nil, partition_key = nil)
34
34
  @cql = cql
35
- @params_metadata = params_metadata
35
+ @params_types = params_types
36
36
  @result_metadata = result_metadata
37
37
  @params = params
38
38
  @keyspace = keyspace
@@ -24,8 +24,6 @@ module Cassandra
24
24
  # @return [String] original cql used to prepare this statement
25
25
  attr_reader :cql
26
26
  # @private
27
- attr_reader :params_metadata
28
- # @private
29
27
  attr_reader :result_metadata
30
28
 
31
29
  # @private
@@ -44,22 +42,52 @@ module Cassandra
44
42
  @schema = schema
45
43
  end
46
44
 
45
+ # @!method bind(args)
47
46
  # Creates a statement bound with specific arguments
48
- # @param args [*Object] arguments to bind, must contain the same number
49
- # of parameters as the number of positional arguments (`?`) in the
50
- # original cql passed to {Cassandra::Session#prepare}
47
+ #
48
+ # @param args [Array] positional arguments to bind, must contain the same
49
+ # number of parameters as the number of positional (`?`) markers in the
50
+ # original CQL passed to {Cassandra::Session#prepare}
51
+ #
52
+ # @note Positional arguments are only supported on Apache Cassandra 2.1
53
+ # and above.
54
+ #
55
+ # @overload bind(*args)
56
+ # Creates a statement bound with specific arguments using the
57
+ # deprecated splat-style way of passing positional arguments.
58
+ #
59
+ # @deprecated Please pass a single {Array} of positional arguments, the
60
+ # `*args` style is deprecated.
61
+ #
62
+ # @param args [*Object] **this style of positional arguments is
63
+ # deprecated, please pass a single {Array} instead** - positional
64
+ # arguments to bind, must contain the same number of parameters as
65
+ # the number of positional argument markers (`?`) in the CQL passed
66
+ # to {Cassandra::Session#prepare}.
67
+ #
51
68
  # @return [Cassandra::Statements::Bound] bound statement
52
69
  def bind(*args)
70
+ if args.one? && args.first.is_a?(::Array)
71
+ args = args.first
72
+ else
73
+ unless args.empty?
74
+ ::Kernel.warn "[WARNING] Splat style (*args) positional " \
75
+ "arguments are deprecated, pass an Array instead " \
76
+ "- called from #{caller.first}"
77
+ end
78
+ end
79
+
53
80
  Util.assert_equal(@params_metadata.size, args.size) { "expecting exactly #{@params_metadata.size} bind parameters, #{args.size} given" }
54
81
 
55
- @params_metadata.each_with_index do |metadata, i|
56
- Util.assert_type(metadata[3], args[i]) { "argument for #{metadata[2].inspect} must be #{metadata[3].inspect}, #{args[i]} given" }
82
+ params_types = @params_metadata.each_with_index.map do |(_, _, name, type), i|
83
+ Util.assert_type(type, args[i]) { "argument for #{name.inspect} must be #{type.inspect}, #{args[i]} given" }
84
+ type
57
85
  end
58
86
 
59
- return Bound.new(@cql, @params_metadata, @result_metadata, args) if @params_metadata.empty?
87
+ return Bound.new(@cql, params_types, @result_metadata, args) if @params_metadata.empty?
60
88
 
61
89
  keyspace, table, _, _ = @params_metadata.first
62
- return Bound.new(@cql, @params_metadata, @result_metadata, args, keyspace) unless keyspace && table
90
+ return Bound.new(@cql, params_types, @result_metadata, args, keyspace) unless keyspace && table
63
91
 
64
92
  values = ::Hash.new
65
93
  @params_metadata.zip(args) do |(keyspace, table, column, type), value|
@@ -68,7 +96,7 @@ module Cassandra
68
96
 
69
97
  partition_key = @schema.create_partition_key(keyspace, table, values)
70
98
 
71
- Bound.new(@cql, @params_metadata, @result_metadata, args, keyspace, partition_key)
99
+ Bound.new(@cql, params_types, @result_metadata, args, keyspace, partition_key)
72
100
  end
73
101
 
74
102
  # @return [Cassandra::Execution::Info] execution info for PREPARE request
@@ -26,8 +26,26 @@ module Cassandra
26
26
  # @return [Array<Object>] a list of positional parameters for the cql
27
27
  attr_reader :params
28
28
 
29
+ # @private
30
+ attr_reader :params_types
31
+
32
+ # @!method initialize(cql, params)
29
33
  # @param cql [String] a cql statement
30
- # @param params [*Object] positional arguments for the query
34
+ # @param params [Array] positional arguments for the query
35
+ #
36
+ # @note Positional arguments for simple statements are only supported on
37
+ # starting with Apache Cassandra 2.0 and above.
38
+ #
39
+ # @overload initialize(cql, *params)
40
+ # Uses the deprecated splat-style way of passing positional arguments.
41
+ #
42
+ # @deprecated Please pass a single {Array} of positional arguments, the
43
+ # `*params` style is deprecated.
44
+ #
45
+ # @param cql [String] a cql statement
46
+ # @param params [*Object] **this style of positional arguments is
47
+ # deprecated, please pass a single {Array} instead** - positional
48
+ # arguments for the query
31
49
  #
32
50
  # @raise [ArgumentError] if cql statement given is not a String
33
51
  def initialize(cql, *params)
@@ -35,8 +53,21 @@ module Cassandra
35
53
  raise ::ArgumentError, "cql must be a string, #{cql.inspect} given"
36
54
  end
37
55
 
38
- @cql = cql
39
- @params = params
56
+ if params.one? && params.first.is_a?(::Array)
57
+ params = params.first
58
+ else
59
+ unless params.empty?
60
+ ::Kernel.warn "[WARNING] Splat style (*params) positional " \
61
+ "arguments are deprecated, pass an Array instead " \
62
+ "- called from #{caller.first}"
63
+ end
64
+ end
65
+
66
+ params_types = params.map {|value| guess_type(value)}
67
+
68
+ @cql = cql
69
+ @params = params
70
+ @params_types = params_types
40
71
  end
41
72
 
42
73
  # @return [String] a CLI-friendly simple statement representation
@@ -53,6 +84,44 @@ module Cassandra
53
84
  end
54
85
 
55
86
  alias :== :eql?
87
+
88
+ private
89
+
90
+ # @private
91
+ @@type_guesses = {
92
+ ::String => :varchar,
93
+ ::Fixnum => :bigint,
94
+ ::Float => :double,
95
+ ::Bignum => :varint,
96
+ ::BigDecimal => :decimal,
97
+ ::TrueClass => :boolean,
98
+ ::FalseClass => :boolean,
99
+ ::NilClass => :bigint,
100
+ Uuid => :uuid,
101
+ TimeUuid => :uuid,
102
+ ::IPAddr => :inet,
103
+ ::Time => :timestamp,
104
+ ::Hash => :map,
105
+ ::Array => :list,
106
+ ::Set => :set,
107
+ }.freeze
108
+
109
+ def guess_type(value)
110
+ type = @@type_guesses[value.class]
111
+
112
+ raise ::ArgumentError, "Unable to guess the type of the argument: #{value.inspect}" unless type
113
+
114
+ if type == :map
115
+ pair = value.first
116
+ [type, guess_type(pair[0]), guess_type(pair[1])]
117
+ elsif type == :list
118
+ [type, guess_type(value.first)]
119
+ elsif type == :set
120
+ [type, guess_type(value.first)]
121
+ else
122
+ type
123
+ end
124
+ end
56
125
  end
57
126
  end
58
127
  end
@@ -261,7 +261,7 @@ module Cassandra
261
261
 
262
262
  buffer = Protocol::CqlByteBuffer.new
263
263
 
264
- TYPE_CONVERTER.to_bytes(buffer, column.type, values[column_name])
264
+ Protocol::Coder.write_value_v1(buffer, values[column_name], column.type)
265
265
  buffer.discard(4)
266
266
  else
267
267
  buf = nil
@@ -274,7 +274,7 @@ module Cassandra
274
274
  buf ||= Protocol::CqlByteBuffer.new
275
275
  buffer ||= Protocol::CqlByteBuffer.new
276
276
 
277
- TYPE_CONVERTER.to_bytes(buf, column.type, values[column_name])
277
+ Protocol::Coder.write_value_v1(buf, values[column_name], column.type)
278
278
  buf.discard(4) # discard size
279
279
 
280
280
  size = buf.length
@@ -289,7 +289,6 @@ module Cassandra
289
289
  private
290
290
 
291
291
  NULL_BYTE = "\x00".freeze
292
- TYPE_CONVERTER = Protocol::TypeConverter.new
293
292
 
294
293
  attr_reader :partition_key, :clustering_columns, :clustering_order
295
294
  protected :partition_key, :clustering_columns, :clustering_order
@@ -132,6 +132,22 @@ module Cassandra
132
132
  io.string
133
133
  end
134
134
 
135
+ def type_to_cql(type)
136
+ case type
137
+ when Array
138
+ case type[0]
139
+ when :list, :set
140
+ "#{type[0].to_s}<#{type_to_cql(type[1])}>"
141
+ when :map
142
+ "#{type[0].to_s}<#{type_to_cql(type[1])}, #{type_to_cql(type[2])}>"
143
+ else
144
+ type.to_s
145
+ end
146
+ else
147
+ type.to_s
148
+ end
149
+ end
150
+
135
151
  def escape_name(name)
136
152
  return name if name[LOWERCASE_REGEXP] == name
137
153
  DBL_QUOT + name + DBL_QUOT
@@ -159,6 +175,8 @@ module Cassandra
159
175
  assert_type(type[1], k)
160
176
  assert_type(type[2], v)
161
177
  end
178
+ when :custom
179
+ assert_responds_to_all([:bytesize, :to_s], value, message, &block)
162
180
  else
163
181
  raise ::RuntimeError, "unsupported complex type #{type.inspect}"
164
182
  end
@@ -17,5 +17,5 @@
17
17
  #++
18
18
 
19
19
  module Cassandra
20
- VERSION = '1.2.0'.freeze
20
+ VERSION = '2.0.0'.freeze
21
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandra-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo Hultberg
@@ -116,10 +116,9 @@ files:
116
116
  - lib/cassandra/load_balancing/policies/white_list.rb
117
117
  - lib/cassandra/null_logger.rb
118
118
  - lib/cassandra/protocol.rb
119
+ - lib/cassandra/protocol/coder.rb
119
120
  - lib/cassandra/protocol/cql_byte_buffer.rb
120
121
  - lib/cassandra/protocol/cql_protocol_handler.rb
121
- - lib/cassandra/protocol/frame_decoder.rb
122
- - lib/cassandra/protocol/frame_encoder.rb
123
122
  - lib/cassandra/protocol/request.rb
124
123
  - lib/cassandra/protocol/requests/auth_response_request.rb
125
124
  - lib/cassandra/protocol/requests/batch_request.rb
@@ -132,14 +131,15 @@ files:
132
131
  - lib/cassandra/protocol/requests/startup_request.rb
133
132
  - lib/cassandra/protocol/requests/void_query_request.rb
134
133
  - lib/cassandra/protocol/response.rb
134
+ - lib/cassandra/protocol/responses/already_exists_error_response.rb
135
135
  - lib/cassandra/protocol/responses/auth_challenge_response.rb
136
136
  - lib/cassandra/protocol/responses/auth_success_response.rb
137
137
  - lib/cassandra/protocol/responses/authenticate_response.rb
138
- - lib/cassandra/protocol/responses/detailed_error_response.rb
139
138
  - lib/cassandra/protocol/responses/error_response.rb
140
139
  - lib/cassandra/protocol/responses/event_response.rb
141
140
  - lib/cassandra/protocol/responses/prepared_result_response.rb
142
141
  - lib/cassandra/protocol/responses/raw_rows_result_response.rb
142
+ - lib/cassandra/protocol/responses/read_timeout_error_response.rb
143
143
  - lib/cassandra/protocol/responses/ready_response.rb
144
144
  - lib/cassandra/protocol/responses/result_response.rb
145
145
  - lib/cassandra/protocol/responses/rows_result_response.rb
@@ -149,8 +149,11 @@ files:
149
149
  - lib/cassandra/protocol/responses/status_change_event_response.rb
150
150
  - lib/cassandra/protocol/responses/supported_response.rb
151
151
  - lib/cassandra/protocol/responses/topology_change_event_response.rb
152
+ - lib/cassandra/protocol/responses/unavailable_error_response.rb
153
+ - lib/cassandra/protocol/responses/unprepared_error_response.rb
152
154
  - lib/cassandra/protocol/responses/void_result_response.rb
153
- - lib/cassandra/protocol/type_converter.rb
155
+ - lib/cassandra/protocol/responses/write_timeout_error_response.rb
156
+ - lib/cassandra/protocol/v1.rb
154
157
  - lib/cassandra/reconnection.rb
155
158
  - lib/cassandra/reconnection/policies.rb
156
159
  - lib/cassandra/reconnection/policies/constant.rb
@@ -1,128 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Protocol
21
- # @private
22
- class FrameDecoder
23
- def initialize(compressor=nil)
24
- @compressor = compressor
25
- end
26
-
27
- def decode_frame(buffer, partial_frame=nil)
28
- partial_frame ||= NULL_FRAME
29
- if partial_frame == NULL_FRAME
30
- buffer_length = buffer.length
31
- return NULL_FRAME if buffer_length < 8
32
- fields = buffer.read_int
33
- size = buffer.read_int
34
- if buffer_length - 8 >= size
35
- actual_decode(buffer, fields, size)
36
- else
37
- PartialFrame.new(fields, size)
38
- end
39
- elsif buffer.length >= partial_frame.size
40
- actual_decode(buffer, partial_frame.fields, partial_frame.size)
41
- else
42
- partial_frame
43
- end
44
- end
45
-
46
- private
47
-
48
- def actual_decode(buffer, fields, size)
49
- if (fields >> 24) & 0x80 == 0
50
- raise Errors::DecodingError, 'Request frames are not supported'
51
- end
52
- protocol_version = (fields >> 24) & 0x7f
53
- compression = (fields >> 16) & 0x01
54
- tracing = (fields >> 16) & 0x02
55
- stream_id = (fields >> 8) & 0xff
56
- stream_id = (stream_id & 0x7f) - (stream_id & 0x80)
57
- opcode = fields & 0xff
58
- if compression == 1
59
- buffer = decompress(buffer, size)
60
- size = buffer.size
61
- end
62
- if tracing == 2
63
- trace_id = buffer.read_uuid
64
- size -= 16
65
- else
66
- trace_id = nil
67
- end
68
- extra_length = buffer.length - size
69
- response = Response.decode(opcode, protocol_version, buffer, size, trace_id)
70
- if buffer.length > extra_length
71
- buffer.discard(buffer.length - extra_length)
72
- end
73
- CompleteFrame.new(stream_id, response)
74
- end
75
-
76
- def decompress(buffer, size)
77
- if @compressor
78
- compressed_body = buffer.read(size)
79
- CqlByteBuffer.new(@compressor.decompress(compressed_body))
80
- else
81
- raise Errors::DecodingError, 'Compressed frame received, but no compressor configured'
82
- end
83
- end
84
-
85
- class NullFrame
86
- def size
87
- nil
88
- end
89
-
90
- def complete?
91
- false
92
- end
93
- end
94
-
95
- class PartialFrame
96
- attr_reader :fields, :size
97
-
98
- def initialize(fields, size)
99
- @fields = fields
100
- @size = size
101
- end
102
-
103
- def stream_id
104
- nil
105
- end
106
-
107
- def complete?
108
- false
109
- end
110
- end
111
-
112
- class CompleteFrame
113
- attr_reader :stream_id, :body
114
-
115
- def initialize(stream_id, body)
116
- @stream_id = stream_id
117
- @body = body
118
- end
119
-
120
- def complete?
121
- true
122
- end
123
- end
124
-
125
- NULL_FRAME = NullFrame.new
126
- end
127
- end
128
- end