cassandra-driver 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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