cql-rb 2.0.5 → 2.1.0.pre0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 076ceeab9f5eff0e9ab577f1e433b087342a8457
4
- data.tar.gz: 049f3ecd2f935016bdd4bb08a87648163609600b
3
+ metadata.gz: 8f408afa031a9e58aebb3be39e8d0c0d2b0ad33b
4
+ data.tar.gz: 7312ad424a8fd77f81af3cbb356018a7a5154d3a
5
5
  SHA512:
6
- metadata.gz: e08c27d6a73bd4fc11573958ae2216affc238180d90d92c32aee98b20103a8614e6c1b693845b000c465b4ba9fd04b25c45a9ba012535a91e635974d832c66e5
7
- data.tar.gz: 0e897851f1dab23f7eaa7ac1380071f4fa2bf0511a16911a5976156d197a533ba83b0fc05a2ee925050b9bc8b96f3ebf31a937158eddd222503b6e68c5343a7d
6
+ metadata.gz: 774a0d581565ad62dbb963e77811431aeb360ec54fea83ec0bba98fe3502e4de076db0bdf9b67494da0b624e5d773c58fd13ae6e0f62b733b749b5392043bf83
7
+ data.tar.gz: 012108242af73ebc3c32d17016e1fcd1667c4b1c16b25206ad6fa462e5c7e04d4848f24649881711089e6d9dcc40eb76d2639082966e64f6da5364bc29ef6ba1
data/README.md CHANGED
@@ -1,3 +1,15 @@
1
+ # This is not the Cassandra driver you are looking for
2
+
3
+ cql-rb has graduated from community driver to being the foundation of the official [Datastax Ruby Driver for Apache Cassandra](https://github.com/datastax/ruby-driver).
4
+
5
+ There will be no more development in this repository, with the exception of critical bug fixes. I encourage everyone to start migrating to the new driver as soon as you can, it's got some great new features that you should try out.
6
+
7
+ The cql-rb code and the old readme will remain here as legacy documentation.
8
+
9
+ Read [the announcement of the new Ruby driver](http://www.datastax.com/dev/blog/ruby-driver-beta-1-release) or [the documentation with all the new features](http://datastax.github.io/ruby-driver/).
10
+
11
+ ---
12
+
1
13
  # Ruby CQL3 driver
2
14
 
3
15
  [![Build Status](https://travis-ci.org/iconara/cql-rb.png?branch=master)](https://travis-ci.org/iconara/cql-rb)
data/lib/cql.rb CHANGED
@@ -17,7 +17,6 @@ module Cql
17
17
  Io = Ione::Io
18
18
  end
19
19
 
20
- require 'cql/error_codes'
21
20
  require 'cql/uuid'
22
21
  require 'cql/time_uuid'
23
22
  require 'cql/compression'
@@ -6,8 +6,6 @@ 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
- include ErrorCodes
10
-
11
9
  attr_reader :code, :cql, :details
12
10
 
13
11
  def initialize(code, message, cql=nil, details=nil)
@@ -224,7 +224,9 @@ module Cql
224
224
  @connection_manager = ConnectionManager.new
225
225
  @execute_options_decoder = ExecuteOptionsDecoder.new(options[:default_consistency] || DEFAULT_CONSISTENCY)
226
226
  @port = options[:port] || DEFAULT_PORT
227
- @connection_timeout = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
227
+ @connection_options = {}
228
+ @connection_options[:timeout] = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
229
+ @connection_options[:ssl] = options[:ssl] if options[:ssl]
228
230
  @credentials = options[:credentials]
229
231
  @auth_provider = options[:auth_provider] || @credentials && Auth::PlainTextAuthProvider.new(*@credentials.values_at(:username, :password))
230
232
  @connected = false
@@ -352,7 +354,7 @@ module Cql
352
354
  protocol_handler_factory = lambda { |connection| Protocol::CqlProtocolHandler.new(connection, @io_reactor, @protocol_version, @compressor) }
353
355
  ClusterConnector.new(
354
356
  Connector.new([
355
- ConnectStep.new(@io_reactor, protocol_handler_factory, @port, @connection_timeout, @logger),
357
+ ConnectStep.new(@io_reactor, protocol_handler_factory, @port, @connection_options, @logger),
356
358
  CacheOptionsStep.new,
357
359
  InitializeStep.new(cql_version, @compressor, @logger),
358
360
  authentication_step,
@@ -365,7 +367,7 @@ module Cql
365
367
  def connect_with_protocol_version_fallback
366
368
  f = create_cluster_connector.connect_all(@hosts, @connections_per_node)
367
369
  f.fallback do |error|
368
- if error.is_a?(QueryError) && error.code == QueryError::PROTOCOL_ERROR && @protocol_version > 1
370
+ if error.is_a?(QueryError) && error.code == 0x0a && @protocol_version > 1
369
371
  @logger.warn('Could not connect using protocol version %d (will try again with %d): %s' % [@protocol_version, @protocol_version - 1, error.message])
370
372
  @protocol_version -= 1
371
373
  connect_with_protocol_version_fallback
@@ -24,7 +24,7 @@ module Cql
24
24
  connected_connections = connections.select(&:connected?)
25
25
  if connected_connections.empty?
26
26
  e = connections.first.error
27
- if e.is_a?(QueryError) && e.code == QueryError::BAD_CREDENTIALS
27
+ if e.is_a?(Cql::QueryError) && e.code == 0x100
28
28
  e = AuthenticationError.new(e.message)
29
29
  end
30
30
  raise e
@@ -72,17 +72,17 @@ module Cql
72
72
 
73
73
  # @private
74
74
  class ConnectStep
75
- def initialize(io_reactor, protocol_handler_factory, port, connection_timeout, logger)
75
+ def initialize(io_reactor, protocol_handler_factory, port, connection_options, logger)
76
76
  @io_reactor = io_reactor
77
77
  @protocol_handler_factory = protocol_handler_factory
78
78
  @port = port
79
- @connection_timeout = connection_timeout
79
+ @connection_options = connection_options
80
80
  @logger = logger
81
81
  end
82
82
 
83
83
  def run(pending_connection)
84
84
  @logger.debug('Connecting to node at %s:%d' % [pending_connection.host, @port])
85
- @io_reactor.connect(pending_connection.host, @port, @connection_timeout, &@protocol_handler_factory).map do |connection|
85
+ @io_reactor.connect(pending_connection.host, @port, @connection_options, &@protocol_handler_factory).map do |connection|
86
86
  pending_connection.with_connection(connection)
87
87
  end
88
88
  end
@@ -150,13 +150,7 @@ module Cql
150
150
  def execute(*args)
151
151
  connection = @connection_manager.random_connection
152
152
  if connection[self]
153
- f = run(args, connection)
154
- f.fallback do |e|
155
- raise e unless e.is_a?(QueryError) && e.code == QueryError::UNPREPARED
156
- prepare(connection).flat_map do
157
- run(args, connection)
158
- end
159
- end
153
+ run(args, connection)
160
154
  else
161
155
  prepare(connection).flat_map do
162
156
  run(args, connection)
@@ -222,12 +216,11 @@ module Cql
222
216
  private
223
217
 
224
218
  def run(args, connection)
225
- bound_args = args.take(@raw_metadata.size)
226
- remaining_args = args.drop(@raw_metadata.size)
227
- unless bound_args.size == @raw_metadata.size && remaining_args.size <= 1
219
+ bound_args = args.shift(@raw_metadata.size)
220
+ unless bound_args.size == @raw_metadata.size && args.size <= 1
228
221
  raise ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
229
222
  end
230
- options = @execute_options_decoder.decode_options(remaining_args.last)
223
+ options = @execute_options_decoder.decode_options(args.last)
231
224
  statement_id = connection[self]
232
225
  request_metadata = @raw_result_metadata.nil?
233
226
  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])
@@ -43,6 +43,7 @@ end
43
43
 
44
44
  require 'cql/protocol/cql_byte_buffer'
45
45
  require 'cql/protocol/type_converter'
46
+ require 'cql/protocol/custom_type_parser'
46
47
  require 'cql/protocol/response'
47
48
  require 'cql/protocol/responses/auth_challenge_response'
48
49
  require 'cql/protocol/responses/auth_success_response'
@@ -203,6 +203,7 @@ module Cql
203
203
  complete_request(id, @current_frame.body)
204
204
  end
205
205
  @current_frame = @frame_decoder.decode_frame(@read_buffer)
206
+ flush_request_queue
206
207
  end
207
208
  end
208
209
 
@@ -232,7 +233,6 @@ module Cql
232
233
  if response.is_a?(Protocol::SetKeyspaceResultResponse)
233
234
  @keyspace = response.keyspace
234
235
  end
235
- flush_request_queue
236
236
  unless promise.timed_out?
237
237
  promise.fulfill(response)
238
238
  end
@@ -256,7 +256,7 @@ module Cql
256
256
  if @request_queue_out.any? && (id = next_stream_id)
257
257
  promise = @request_queue_out.shift
258
258
  if promise.timed_out?
259
- next
259
+ id = nil
260
260
  else
261
261
  frame = promise.frame
262
262
  @promises[id] = promise
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class CustomTypeParser
6
+ def parse_type(str)
7
+ parse_custom_type(str).first
8
+ end
9
+
10
+ private
11
+
12
+ def parse_custom_type(str)
13
+ open_parentheses_index = str.index('(')
14
+ if open_parentheses_index
15
+ type = str[0, open_parentheses_index]
16
+ rest = str[open_parentheses_index + 1, str.bytesize - open_parentheses_index - 1]
17
+ if type == USER_TYPE
18
+ start_index = str.index(',', str.index(',') + 1)
19
+ rest = str[start_index + 1, str.bytesize - start_index - 1]
20
+ field_types, rest = parse_user_type_fields(rest)
21
+ rest = rest && rest[0, rest.bytesize - 1]
22
+ [[:udt, Hash[field_types]], rest]
23
+ elsif type == LIST_TYPE
24
+ type, rest = parse_custom_type(rest)
25
+ rest = rest && rest[1, rest.bytesize - 1]
26
+ [[:list, type], rest]
27
+ elsif type == MAP_TYPE
28
+ key_type, value_type, rest = parse_map_fields(rest)
29
+ rest = rest && rest[1, rest.bytesize - 1]
30
+ [[:map, key_type, value_type], rest]
31
+ elsif type == SET_TYPE
32
+ type, rest = parse_custom_type(rest)
33
+ rest = rest && rest[1, rest.bytesize - 1]
34
+ [[:set, type], rest]
35
+ else
36
+ [nil, rest]
37
+ end
38
+ else
39
+ type = SCALAR_TYPES.keys.find do |type|
40
+ str.start_with?(type)
41
+ end
42
+ if type
43
+ rest = str[type.bytesize, str.bytesize - str.bytesize]
44
+ [SCALAR_TYPES[type], rest]
45
+ else
46
+ [[:custom, str], nil]
47
+ end
48
+ end
49
+ end
50
+
51
+ def parse_user_type_fields(str)
52
+ return [[], str] if str.nil? || str.empty?
53
+ comma_index = str.index(',')
54
+ open_parentheses_index = str.index('(')
55
+ close_parentheses_index = str.index(')')
56
+ if close_parentheses_index == 0
57
+ return [[], str]
58
+ elsif open_parentheses_index && (comma_index.nil? || comma_index > open_parentheses_index)
59
+ end_index = open_parentheses_index
60
+ elsif comma_index && (close_parentheses_index.nil? || close_parentheses_index > comma_index)
61
+ end_index = comma_index
62
+ else
63
+ end_index = close_parentheses_index
64
+ end
65
+ field = str[0, end_index]
66
+ name, type = field.split(':')
67
+ name = [name].pack('H*')
68
+ rest = str[end_index + 1, str.bytesize - end_index - 1]
69
+ if end_index == open_parentheses_index
70
+ colon_index = field.index(':')
71
+ type, rest = parse_custom_type(str[colon_index + 1, str.bytesize - colon_index - 1])
72
+ types, rest = parse_user_type_fields(rest)
73
+ elsif end_index == comma_index
74
+ types, rest = parse_user_type_fields(rest)
75
+ type = SCALAR_TYPES[type]
76
+ else
77
+ type = SCALAR_TYPES[type]
78
+ end
79
+ [[[name, type], *types], rest]
80
+ end
81
+
82
+ def parse_map_fields(str)
83
+ key_type, rest = parse_custom_type(str)
84
+ rest = rest[1, rest.bytesize - 1]
85
+ value_type, rest = parse_custom_type(rest)
86
+ [key_type, value_type, rest]
87
+ end
88
+
89
+ LIST_TYPE = 'org.apache.cassandra.db.marshal.ListType'.freeze
90
+ MAP_TYPE = 'org.apache.cassandra.db.marshal.MapType'.freeze
91
+ SET_TYPE = 'org.apache.cassandra.db.marshal.SetType'.freeze
92
+ USER_TYPE = 'org.apache.cassandra.db.marshal.UserType'.freeze
93
+
94
+ SCALAR_TYPES = {
95
+ 'org.apache.cassandra.db.marshal.AsciiType' => :ascii,
96
+ 'org.apache.cassandra.db.marshal.BooleanType' => :boolean,
97
+ 'org.apache.cassandra.db.marshal.BytesType' => :bytes,
98
+ 'org.apache.cassandra.db.marshal.CounterColumnType' => :counter,
99
+ 'org.apache.cassandra.db.marshal.DateType' => :date,
100
+ 'org.apache.cassandra.db.marshal.DecimalType' => :decimal,
101
+ 'org.apache.cassandra.db.marshal.DoubleType' => :double,
102
+ 'org.apache.cassandra.db.marshal.FloatType' => :float,
103
+ 'org.apache.cassandra.db.marshal.InetAddressType' => :inet,
104
+ 'org.apache.cassandra.db.marshal.Int32Type' => :int,
105
+ 'org.apache.cassandra.db.marshal.IntegerType' => :int,
106
+ 'org.apache.cassandra.db.marshal.LongType' => :bigint,
107
+ 'org.apache.cassandra.db.marshal.TimeUUIDType' => :time_uuid,
108
+ 'org.apache.cassandra.db.marshal.TimestampType' => :timestamp,
109
+ 'org.apache.cassandra.db.marshal.UTF8Type' => :text,
110
+ 'org.apache.cassandra.db.marshal.UUIDType' => :uuid,
111
+ }.freeze
112
+ end
113
+ end
114
+ end
@@ -13,24 +13,24 @@ module Cql
13
13
  def self.decode(code, message, protocol_version, buffer, length, trace_id=nil)
14
14
  details = {}
15
15
  case code
16
- when UNAVAILABLE
16
+ when 0x1000 # unavailable
17
17
  details[:cl] = buffer.read_consistency
18
18
  details[:required] = buffer.read_int
19
19
  details[:alive] = buffer.read_int
20
- when WRITE_TIMEOUT
20
+ when 0x1100 # write_timeout
21
21
  details[:cl] = buffer.read_consistency
22
22
  details[:received] = buffer.read_int
23
23
  details[:blockfor] = buffer.read_int
24
24
  details[:write_type] = buffer.read_string
25
- when READ_TIMEOUT
25
+ when 0x1200 # read_timeout
26
26
  details[:cl] = buffer.read_consistency
27
27
  details[:received] = buffer.read_int
28
28
  details[:blockfor] = buffer.read_int
29
29
  details[:data_present] = buffer.read_byte != 0
30
- when ALREADY_EXISTS
30
+ when 0x2400 # already_exists
31
31
  details[:ks] = buffer.read_string
32
32
  details[:table] = buffer.read_string
33
- when UNPREPARED
33
+ when 0x2500
34
34
  details[:id] = buffer.read_short_bytes
35
35
  end
36
36
  new(code, message, details)
@@ -3,8 +3,6 @@
3
3
  module Cql
4
4
  module Protocol
5
5
  class ErrorResponse < Response
6
- include ErrorCodes
7
-
8
6
  attr_reader :code, :message
9
7
 
10
8
  def initialize(*args)
@@ -15,7 +13,7 @@ module Cql
15
13
  code = buffer.read_int
16
14
  message = buffer.read_string
17
15
  case code
18
- when UNAVAILABLE, WRITE_TIMEOUT, READ_TIMEOUT, ALREADY_EXISTS, UNPREPARED
16
+ when 0x1000, 0x1100, 0x1200, 0x2400, 0x2500
19
17
  new_length = length - 4 - 4 - message.bytesize
20
18
  DetailedErrorResponse.decode(code, message, protocol_version, buffer, new_length)
21
19
  else
@@ -51,6 +51,7 @@ module Cql
51
51
  ].freeze
52
52
 
53
53
  TYPE_CONVERTER = TypeConverter.new
54
+ CUSTOM_TYPE_PARSER = CustomTypeParser.new
54
55
 
55
56
  GLOBAL_TABLES_SPEC_FLAG = 0x01
56
57
  HAS_MORE_PAGES_FLAG = 0x02
@@ -58,7 +59,9 @@ module Cql
58
59
 
59
60
  def self.read_column_type(buffer)
60
61
  id, type = buffer.read_option do |id, b|
61
- if id > 0 && id <= 0x10
62
+ if id == 0
63
+ CUSTOM_TYPE_PARSER.parse_type(buffer.read_string)
64
+ elsif id > 0 && id <= 0x10
62
65
  COLUMN_TYPES[id]
63
66
  elsif id == 0x20
64
67
  sub_type = read_column_type(buffer)
@@ -12,56 +12,79 @@ module Cql
12
12
  @to_bytes_converters = to_bytes_converters
13
13
  end
14
14
 
15
- def from_bytes(buffer, type, size_bytes=4)
15
+ def from_bytes(buffer, type, size_bytes=4, override_size=false)
16
16
  return nil if buffer.empty?
17
17
  case type
18
18
  when Array
19
- return nil unless read_size(buffer, size_bytes)
19
+ size = read_size(buffer, size_bytes)
20
+ return nil unless size
21
+ size_bytes = override_size ? size_bytes : 2
20
22
  case type.first
21
23
  when :list
22
- bytes_to_list(buffer, @from_bytes_converters[type[1]])
24
+ bytes_to_list(buffer, type[1], size_bytes, override_size)
23
25
  when :map
24
- bytes_to_map(buffer, @from_bytes_converters[type[1]], @from_bytes_converters[type[2]])
26
+ bytes_to_map(buffer, type[1], type[2], size_bytes, override_size)
25
27
  when :set
26
- bytes_to_set(buffer, @from_bytes_converters[type[1]])
28
+ bytes_to_set(buffer, type[1], size_bytes, override_size)
29
+ when :udt
30
+ bytes_to_udt_value(buffer, type)
31
+ when :custom
32
+ bytes_to_custom(buffer, size)
27
33
  end
28
34
  else
29
35
  @from_bytes_converters[type].call(buffer, size_bytes)
30
36
  end
31
37
  end
32
38
 
33
- def to_bytes(buffer, type, value, size_bytes=4)
39
+ def to_bytes(buffer, type, value, size_bytes=4, override_size=false)
34
40
  case type
35
41
  when Array
36
- unless value.nil? || value.is_a?(Enumerable)
37
- raise InvalidValueError, 'Value for collection must be enumerable'
38
- end
39
42
  case type.first
40
43
  when :list, :set
44
+ unless value.nil? || value.is_a?(Enumerable)
45
+ raise InvalidValueError, 'Value for %s must be enumerable' % type
46
+ end
41
47
  _, sub_type = type
42
48
  if value
49
+ size_bytes = override_size ? size_bytes : 2
43
50
  raw = CqlByteBuffer.new
44
- raw.append_short(value.size)
51
+ if size_bytes == 2
52
+ raw.append_short(value.size)
53
+ else
54
+ raw.append_int(value.size)
55
+ end
45
56
  value.each do |element|
46
- to_bytes(raw, sub_type, element, 2)
57
+ to_bytes(raw, sub_type, element, size_bytes, override_size)
47
58
  end
48
59
  buffer.append_bytes(raw)
49
60
  else
50
61
  nil_to_bytes(buffer, size_bytes)
51
62
  end
52
63
  when :map
64
+ unless value.nil? || value.is_a?(Enumerable)
65
+ raise InvalidValueError, 'Value for %s must be enumerable' % type
66
+ end
53
67
  _, key_type, value_type = type
54
68
  if value
69
+ size_bytes = override_size ? size_bytes : 2
55
70
  raw = CqlByteBuffer.new
56
- raw.append_short(value.size)
71
+ if size_bytes == 2
72
+ raw.append_short(value.size)
73
+ else
74
+ raw.append_int(value.size)
75
+ end
57
76
  value.each do |key, value|
58
- to_bytes(raw, key_type, key, 2)
59
- to_bytes(raw, value_type, value, 2)
77
+ to_bytes(raw, key_type, key, size_bytes, override_size)
78
+ to_bytes(raw, value_type, value, size_bytes, override_size)
60
79
  end
61
80
  buffer.append_bytes(raw)
62
81
  else
63
82
  nil_to_bytes(buffer, size_bytes)
64
83
  end
84
+ when :udt
85
+ udt_to_bytes(buffer, type[1], value, size_bytes)
86
+ when :custom
87
+ custom_to_bytes(buffer, type[1], value, size_bytes)
65
88
  else
66
89
  raise UnsupportedColumnTypeError, %(Unsupported column collection type: #{type.first})
67
90
  end
@@ -205,35 +228,47 @@ module Cql
205
228
  IPAddr.new_ntoh(buffer.read(size))
206
229
  end
207
230
 
208
- def bytes_to_list(buffer, value_converter)
231
+ def bytes_to_list(buffer, subtype, size_bytes, override_size)
209
232
  list = []
210
- size = buffer.read_short
233
+ size = read_size(buffer, size_bytes)
211
234
  size.times do
212
- list << value_converter.call(buffer, 2)
235
+ list << from_bytes(buffer, subtype, size_bytes, override_size)
213
236
  end
214
237
  list
215
238
  end
216
239
 
217
- def bytes_to_map(buffer, key_converter, value_converter)
240
+ def bytes_to_map(buffer, key_type, value_type, size_bytes, override_size)
218
241
  map = {}
219
- size = buffer.read_short
242
+ size = read_size(buffer, size_bytes)
220
243
  size.times do
221
- key = key_converter.call(buffer, 2)
222
- value = value_converter.call(buffer, 2)
244
+ key = from_bytes(buffer, key_type, size_bytes, override_size)
245
+ value = from_bytes(buffer, value_type, size_bytes, override_size)
223
246
  map[key] = value
224
247
  end
225
248
  map
226
249
  end
227
250
 
228
- def bytes_to_set(buffer, value_converter)
251
+ def bytes_to_set(buffer, subtype, size_bytes, override_size)
229
252
  set = Set.new
230
- size = buffer.read_short
253
+ size = read_size(buffer, size_bytes)
231
254
  size.times do
232
- set << value_converter.call(buffer, 2)
255
+ set << from_bytes(buffer, subtype, size_bytes, override_size)
233
256
  end
234
257
  set
235
258
  end
236
259
 
260
+ def bytes_to_udt_value(buffer, type)
261
+ value = {}
262
+ type[1].each do |name, subtype|
263
+ value[name] = from_bytes(buffer, subtype, 4, true)
264
+ end
265
+ value
266
+ end
267
+
268
+ def bytes_to_custom(buffer, size)
269
+ buffer.read(size)
270
+ end
271
+
237
272
  def ascii_to_bytes(buffer, value, size_bytes)
238
273
  v = value && value.encode(::Encoding::ASCII)
239
274
  if size_bytes == 4
@@ -367,6 +402,29 @@ module Cql
367
402
  buffer.append_short(-1)
368
403
  end
369
404
  end
405
+
406
+ def udt_to_bytes(buffer, type, value, size_bytes)
407
+ if value
408
+ offset = buffer.length
409
+ size_to_bytes(buffer, 0, size_bytes)
410
+ type.each do |field_name, field_type|
411
+ field_value = value[field_name]
412
+ to_bytes(buffer, field_type, field_value, 4, true)
413
+ end
414
+ buffer.update(offset, size_to_bytes(CqlByteBuffer.new, buffer.length - offset - size_bytes, size_bytes))
415
+ else
416
+ nil_to_bytes(buffer, size_bytes)
417
+ end
418
+ end
419
+
420
+ def custom_to_bytes(buffer, type, value, size_bytes)
421
+ if value
422
+ size_to_bytes(buffer, value.size, size_bytes)
423
+ buffer.append(value)
424
+ else
425
+ nil_to_bytes(buffer, size_bytes)
426
+ end
427
+ end
370
428
  end
371
429
  end
372
430
  end