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 +4 -4
- data/README.md +12 -0
- data/lib/cql.rb +0 -1
- data/lib/cql/client.rb +0 -2
- data/lib/cql/client/client.rb +5 -3
- data/lib/cql/client/connector.rb +4 -4
- data/lib/cql/client/prepared_statement.rb +4 -11
- data/lib/cql/protocol.rb +1 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +2 -2
- data/lib/cql/protocol/custom_type_parser.rb +114 -0
- data/lib/cql/protocol/responses/detailed_error_response.rb +5 -5
- data/lib/cql/protocol/responses/error_response.rb +1 -3
- data/lib/cql/protocol/responses/rows_result_response.rb +4 -1
- data/lib/cql/protocol/type_converter.rb +82 -24
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/client_spec.rb +7 -0
- data/spec/cql/client/connector_spec.rb +6 -2
- data/spec/cql/client/peer_discovery_spec.rb +3 -3
- data/spec/cql/client/prepared_statement_spec.rb +4 -23
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +0 -31
- data/spec/cql/protocol/custom_type_parser_spec.rb +43 -0
- data/spec/cql/protocol/requests/execute_request_spec.rb +161 -37
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +22 -0
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +187 -0
- data/spec/cql/protocol/type_converter_spec.rb +12 -0
- data/spec/integration/client_spec.rb +60 -8
- data/spec/support/fake_io_reactor.rb +6 -5
- metadata +11 -9
- data/lib/cql/error_codes.rb +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f408afa031a9e58aebb3be39e8d0c0d2b0ad33b
|
4
|
+
data.tar.gz: 7312ad424a8fd77f81af3cbb356018a7a5154d3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
[](https://travis-ci.org/iconara/cql-rb)
|
data/lib/cql.rb
CHANGED
data/lib/cql/client.rb
CHANGED
data/lib/cql/client/client.rb
CHANGED
@@ -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
|
-
@
|
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, @
|
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 ==
|
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
|
data/lib/cql/client/connector.rb
CHANGED
@@ -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 ==
|
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,
|
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
|
-
@
|
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, @
|
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
|
-
|
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.
|
226
|
-
|
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(
|
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])
|
data/lib/cql/protocol.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
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
|
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
|
30
|
+
when 0x2400 # already_exists
|
31
31
|
details[:ks] = buffer.read_string
|
32
32
|
details[:table] = buffer.read_string
|
33
|
-
when
|
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
|
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
|
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
|
-
|
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,
|
24
|
+
bytes_to_list(buffer, type[1], size_bytes, override_size)
|
23
25
|
when :map
|
24
|
-
bytes_to_map(buffer,
|
26
|
+
bytes_to_map(buffer, type[1], type[2], size_bytes, override_size)
|
25
27
|
when :set
|
26
|
-
bytes_to_set(buffer,
|
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
|
-
|
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,
|
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
|
-
|
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,
|
59
|
-
to_bytes(raw, value_type, value,
|
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,
|
231
|
+
def bytes_to_list(buffer, subtype, size_bytes, override_size)
|
209
232
|
list = []
|
210
|
-
size = buffer
|
233
|
+
size = read_size(buffer, size_bytes)
|
211
234
|
size.times do
|
212
|
-
list <<
|
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,
|
240
|
+
def bytes_to_map(buffer, key_type, value_type, size_bytes, override_size)
|
218
241
|
map = {}
|
219
|
-
size = buffer
|
242
|
+
size = read_size(buffer, size_bytes)
|
220
243
|
size.times do
|
221
|
-
key =
|
222
|
-
value =
|
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,
|
251
|
+
def bytes_to_set(buffer, subtype, size_bytes, override_size)
|
229
252
|
set = Set.new
|
230
|
-
size = buffer
|
253
|
+
size = read_size(buffer, size_bytes)
|
231
254
|
size.times do
|
232
|
-
set <<
|
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
|