cql-rb 1.0.6 → 1.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.
- data/README.md +4 -9
- data/lib/cql.rb +1 -0
- data/lib/cql/byte_buffer.rb +23 -7
- data/lib/cql/client.rb +11 -6
- data/lib/cql/client/asynchronous_client.rb +37 -83
- data/lib/cql/client/asynchronous_prepared_statement.rb +10 -4
- data/lib/cql/client/column_metadata.rb +16 -0
- data/lib/cql/client/request_runner.rb +46 -0
- data/lib/cql/future.rb +4 -5
- data/lib/cql/io.rb +2 -5
- data/lib/cql/io/connection.rb +220 -0
- data/lib/cql/io/io_reactor.rb +213 -185
- data/lib/cql/protocol.rb +1 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +201 -0
- data/lib/cql/protocol/decoding.rb +6 -31
- data/lib/cql/protocol/encoding.rb +1 -5
- data/lib/cql/protocol/request.rb +4 -0
- data/lib/cql/protocol/responses/schema_change_result_response.rb +15 -0
- data/lib/cql/protocol/type_converter.rb +56 -76
- data/lib/cql/time_uuid.rb +104 -0
- data/lib/cql/uuid.rb +4 -2
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +47 -71
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +68 -0
- data/spec/cql/client/client_shared.rb +3 -3
- data/spec/cql/client/column_metadata_spec.rb +80 -0
- data/spec/cql/client/request_runner_spec.rb +120 -0
- data/spec/cql/future_spec.rb +26 -11
- data/spec/cql/io/connection_spec.rb +460 -0
- data/spec/cql/io/io_reactor_spec.rb +212 -265
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +216 -0
- data/spec/cql/protocol/decoding_spec.rb +9 -28
- data/spec/cql/protocol/encoding_spec.rb +0 -5
- data/spec/cql/protocol/request_spec.rb +16 -0
- data/spec/cql/protocol/response_frame_spec.rb +2 -2
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +70 -0
- data/spec/cql/time_uuid_spec.rb +136 -0
- data/spec/cql/uuid_spec.rb +1 -5
- data/spec/integration/client_spec.rb +34 -38
- data/spec/integration/io_spec.rb +283 -0
- data/spec/integration/protocol_spec.rb +53 -113
- data/spec/integration/regression_spec.rb +124 -0
- data/spec/integration/uuid_spec.rb +76 -0
- data/spec/spec_helper.rb +12 -9
- data/spec/support/fake_io_reactor.rb +52 -21
- data/spec/support/fake_server.rb +2 -2
- metadata +33 -10
- checksums.yaml +0 -15
- data/lib/cql/io/node_connection.rb +0 -209
- data/spec/cql/protocol/type_converter_spec.rb +0 -52
data/lib/cql/protocol.rb
CHANGED
@@ -0,0 +1,201 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Cql
|
4
|
+
module Protocol
|
5
|
+
# This class wraps a single connection and translates between request/
|
6
|
+
# response frames and raw bytes.
|
7
|
+
#
|
8
|
+
# You send requests with #send_request, and receive responses through the
|
9
|
+
# returned future.
|
10
|
+
#
|
11
|
+
# Instances of this class are thread safe.
|
12
|
+
#
|
13
|
+
# @examle Sending an OPTIONS request
|
14
|
+
# future = protocol_handler.send_request(Cql::Protocol::OptionsRequest.new)
|
15
|
+
# response = future.get
|
16
|
+
# puts "These options are supported: #{response.options}"
|
17
|
+
#
|
18
|
+
class CqlProtocolHandler
|
19
|
+
# @return [String] the current keyspace for the underlying connection
|
20
|
+
attr_reader :keyspace
|
21
|
+
|
22
|
+
def initialize(connection)
|
23
|
+
@connection = connection
|
24
|
+
@connection.on_data(&method(:receive_data))
|
25
|
+
@connection.on_closed(&method(:socket_closed))
|
26
|
+
@responses = Array.new(128) { nil }
|
27
|
+
@read_buffer = ByteBuffer.new
|
28
|
+
@current_frame = Protocol::ResponseFrame.new(@read_buffer)
|
29
|
+
@request_queue_in = []
|
30
|
+
@request_queue_out = []
|
31
|
+
@event_listeners = []
|
32
|
+
@lock = Mutex.new
|
33
|
+
@closed_future = Future.new
|
34
|
+
@keyspace = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [true, false] true if the underlying connection is connected
|
38
|
+
def connected?
|
39
|
+
@connection.connected?
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [true, false] true if the underlying connection is closed
|
43
|
+
def closed?
|
44
|
+
@connection.closed?
|
45
|
+
end
|
46
|
+
|
47
|
+
# Register to receive notification when the underlying connection has
|
48
|
+
# closed. If the connection closed abruptly the error will be passed
|
49
|
+
# to the listener, otherwise it will not receive any parameters.
|
50
|
+
#
|
51
|
+
# @yieldparam error [nil, Error] the error that caused the connection to
|
52
|
+
# close, if any
|
53
|
+
def on_closed(&listener)
|
54
|
+
@closed_future.on_complete(&listener)
|
55
|
+
@closed_future.on_failure(&listener)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Register to receive server sent events, like schema changes, nodes going
|
59
|
+
# up or down, etc. To actually receive events you also need to send a
|
60
|
+
# REGISTER request for the events you wish to receive.
|
61
|
+
#
|
62
|
+
# @yieldparam event [Cql::Protocol::EventResponse] an event sent by the server
|
63
|
+
def on_event(&listener)
|
64
|
+
@lock.synchronize do
|
65
|
+
@event_listeners << listener
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Serializes and send a request over the underlying connection.
|
70
|
+
#
|
71
|
+
# Returns a future that will resolve to the response. When the connection
|
72
|
+
# closes the futures of all active requests will be failed with the error
|
73
|
+
# that caused the connection to close, or nil
|
74
|
+
#
|
75
|
+
# @return [Cql::Future<Cql::Protocol::Response>] a future that resolves to
|
76
|
+
# the response
|
77
|
+
def send_request(request)
|
78
|
+
return Future.failed(NotConnectedError.new) if closed?
|
79
|
+
future = Future.new
|
80
|
+
id = nil
|
81
|
+
@lock.synchronize do
|
82
|
+
if (id = next_stream_id)
|
83
|
+
@responses[id] = future
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if id
|
87
|
+
@connection.write do |buffer|
|
88
|
+
request.encode_frame(id, buffer)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
@lock.synchronize do
|
92
|
+
@request_queue_in << [request.encode_frame(0), future]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
future
|
96
|
+
end
|
97
|
+
|
98
|
+
# Closes the underlying connection.
|
99
|
+
#
|
100
|
+
# @return [Cql::Future] a future that completes when the connection has closed
|
101
|
+
def close
|
102
|
+
@connection.close
|
103
|
+
@closed_future
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def receive_data(data)
|
109
|
+
@current_frame << data
|
110
|
+
while @current_frame.complete?
|
111
|
+
id = @current_frame.stream_id
|
112
|
+
if id == -1
|
113
|
+
notify_event_listeners(@current_frame.body)
|
114
|
+
else
|
115
|
+
complete_request(id, @current_frame.body)
|
116
|
+
end
|
117
|
+
@current_frame = Protocol::ResponseFrame.new(@read_buffer)
|
118
|
+
flush_request_queue
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def notify_event_listeners(event_response)
|
123
|
+
return if @event_listeners.empty?
|
124
|
+
@lock.synchronize do
|
125
|
+
@event_listeners.each do |listener|
|
126
|
+
listener.call(@current_frame.body) rescue nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def complete_request(id, response)
|
132
|
+
future = @lock.synchronize do
|
133
|
+
future = @responses[id]
|
134
|
+
@responses[id] = nil
|
135
|
+
future
|
136
|
+
end
|
137
|
+
if response.is_a?(Protocol::SetKeyspaceResultResponse)
|
138
|
+
@keyspace = response.keyspace
|
139
|
+
end
|
140
|
+
future.complete!(response)
|
141
|
+
end
|
142
|
+
|
143
|
+
def flush_request_queue
|
144
|
+
@lock.synchronize do
|
145
|
+
if @request_queue_out.empty? && !@request_queue_in.empty?
|
146
|
+
@request_queue_out = @request_queue_in
|
147
|
+
@request_queue_in = []
|
148
|
+
end
|
149
|
+
end
|
150
|
+
while true
|
151
|
+
id = nil
|
152
|
+
request_buffer = nil
|
153
|
+
@lock.synchronize do
|
154
|
+
if @request_queue_out.any? && (id = next_stream_id)
|
155
|
+
request_buffer, future = @request_queue_out.shift
|
156
|
+
@responses[id] = future
|
157
|
+
end
|
158
|
+
end
|
159
|
+
if id
|
160
|
+
Protocol::Request.change_stream_id(id, request_buffer)
|
161
|
+
@connection.write(request_buffer)
|
162
|
+
else
|
163
|
+
break
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def socket_closed(cause)
|
169
|
+
request_failure_cause = cause || Io::ConnectionClosedError.new
|
170
|
+
@lock.synchronize do
|
171
|
+
@responses.each_with_index do |future, i|
|
172
|
+
if future
|
173
|
+
@responses[i].fail!(request_failure_cause)
|
174
|
+
@responses[i] = nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
@request_queue_in.each do |_, future|
|
178
|
+
future.fail!(request_failure_cause)
|
179
|
+
end
|
180
|
+
@request_queue_in.clear
|
181
|
+
@request_queue_out.each do |_, future|
|
182
|
+
future.fail!(request_failure_cause)
|
183
|
+
end
|
184
|
+
@request_queue_out.clear
|
185
|
+
if cause
|
186
|
+
@closed_future.fail!(cause)
|
187
|
+
else
|
188
|
+
@closed_future.complete!
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def next_stream_id
|
194
|
+
@responses.each_with_index do |task, index|
|
195
|
+
return index if task.nil?
|
196
|
+
end
|
197
|
+
nil
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -31,34 +31,15 @@ module Cql
|
|
31
31
|
def read_decimal!(buffer, length=buffer.length)
|
32
32
|
size = read_int!(buffer)
|
33
33
|
number_string = read_varint!(buffer, length - 4).to_s
|
34
|
-
|
35
|
-
if number_string.start_with?(MINUS)
|
36
|
-
number_string = number_string[1, number_string.length - 1]
|
37
|
-
fraction_string = MINUS + ZERO << DECIMAL_POINT
|
38
|
-
else
|
39
|
-
fraction_string = ZERO + DECIMAL_POINT
|
40
|
-
end
|
41
|
-
(size - number_string.length).times { fraction_string << ZERO }
|
42
|
-
fraction_string << number_string
|
43
|
-
else
|
44
|
-
fraction_string = number_string[0, number_string.length - size]
|
45
|
-
fraction_string << DECIMAL_POINT
|
46
|
-
fraction_string << number_string[number_string.length - size, number_string.length]
|
47
|
-
end
|
34
|
+
fraction_string = number_string[0, number_string.length - size] << DECIMAL_POINT << number_string[number_string.length - size, number_string.length]
|
48
35
|
BigDecimal.new(fraction_string)
|
49
36
|
rescue RangeError => e
|
50
37
|
raise DecodingError, e.message, e.backtrace
|
51
38
|
end
|
52
39
|
|
53
40
|
def read_long!(buffer)
|
54
|
-
|
55
|
-
|
56
|
-
hi ^= 0xffffffff
|
57
|
-
lo ^= 0xffffffff
|
58
|
-
0 - (hi << 32) - lo - 1
|
59
|
-
else
|
60
|
-
(hi << 32) + lo
|
61
|
-
end
|
41
|
+
top, bottom = buffer.read(8).unpack(Formats::TWO_INTS_FORMAT)
|
42
|
+
(top << 32) | bottom
|
62
43
|
rescue RangeError => e
|
63
44
|
raise DecodingError, e.message, e.backtrace
|
64
45
|
end
|
@@ -76,11 +57,7 @@ module Cql
|
|
76
57
|
end
|
77
58
|
|
78
59
|
def read_int!(buffer)
|
79
|
-
|
80
|
-
if (val > 0x7fffffff)
|
81
|
-
val = 0 - ((val - 1) ^ 0xffffffff)
|
82
|
-
end
|
83
|
-
val
|
60
|
+
buffer.read_int
|
84
61
|
rescue RangeError => e
|
85
62
|
raise DecodingError, "Not enough bytes available to decode an int: #{e.message}", e.backtrace
|
86
63
|
end
|
@@ -109,8 +86,8 @@ module Cql
|
|
109
86
|
raise DecodingError, "Not enough bytes available to decode a long string: #{e.message}", e.backtrace
|
110
87
|
end
|
111
88
|
|
112
|
-
def read_uuid!(buffer)
|
113
|
-
|
89
|
+
def read_uuid!(buffer, impl=Uuid)
|
90
|
+
impl.new(read_varint!(buffer, 16, false))
|
114
91
|
rescue RangeError => e
|
115
92
|
raise DecodingError, "Not enough bytes available to decode a UUID: #{e.message}", e.backtrace
|
116
93
|
end
|
@@ -184,8 +161,6 @@ module Cql
|
|
184
161
|
|
185
162
|
private
|
186
163
|
|
187
|
-
MINUS = '-'.freeze
|
188
|
-
ZERO = '0'.freeze
|
189
164
|
DECIMAL_POINT = '.'.freeze
|
190
165
|
end
|
191
166
|
end
|
@@ -27,11 +27,7 @@ module Cql
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def write_uuid(buffer, uuid)
|
30
|
-
|
31
|
-
write_int(buffer, (v >> 96) & 0xffffffff)
|
32
|
-
write_int(buffer, (v >> 64) & 0xffffffff)
|
33
|
-
write_int(buffer, (v >> 32) & 0xffffffff)
|
34
|
-
write_int(buffer, v & 0xffffffff)
|
30
|
+
write_varint(buffer, uuid.value)
|
35
31
|
end
|
36
32
|
|
37
33
|
def write_string_list(buffer, strs)
|
data/lib/cql/protocol/request.rb
CHANGED
@@ -19,6 +19,10 @@ module Cql
|
|
19
19
|
buffer.update(offset + 4, [(buffer.bytesize - offset - 8)].pack(Formats::INT_FORMAT))
|
20
20
|
buffer
|
21
21
|
end
|
22
|
+
|
23
|
+
def self.change_stream_id(new_stream_id, buffer, offset=0)
|
24
|
+
buffer.update(offset + 2, new_stream_id.chr)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -13,6 +13,21 @@ module Cql
|
|
13
13
|
new(read_string!(buffer), read_string!(buffer), read_string!(buffer))
|
14
14
|
end
|
15
15
|
|
16
|
+
def eql?(other)
|
17
|
+
self.change == other.change && self.keyspace == other.keyspace && self.table == other.table
|
18
|
+
end
|
19
|
+
alias_method :==, :eql?
|
20
|
+
|
21
|
+
def hash
|
22
|
+
@h ||= begin
|
23
|
+
h = 0
|
24
|
+
h = ((h & 0xffffffff) * 31) ^ @change.hash
|
25
|
+
h = ((h & 0xffffffff) * 31) ^ @keyspace.hash
|
26
|
+
h = ((h & 0xffffffff) * 31) ^ @table.hash
|
27
|
+
h
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
16
31
|
def to_s
|
17
32
|
%(RESULT SCHEMA_CHANGE #@change "#@keyspace" "#@table")
|
18
33
|
end
|
@@ -36,35 +36,27 @@ module Cql
|
|
36
36
|
def to_bytes(io, type, value, size_bytes=4)
|
37
37
|
case type
|
38
38
|
when Array
|
39
|
-
unless value.
|
39
|
+
unless value.is_a?(Enumerable)
|
40
40
|
raise InvalidValueError, 'Value for collection must be enumerable'
|
41
41
|
end
|
42
42
|
case type.first
|
43
43
|
when :list, :set
|
44
44
|
_, sub_type = type
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
to_bytes(raw, sub_type, element, 2)
|
50
|
-
end
|
51
|
-
write_bytes(io, raw)
|
52
|
-
else
|
53
|
-
nil_to_bytes(io, size_bytes)
|
45
|
+
raw = ''
|
46
|
+
write_short(raw, value.size)
|
47
|
+
value.each do |element|
|
48
|
+
to_bytes(raw, sub_type, element, 2)
|
54
49
|
end
|
50
|
+
write_bytes(io, raw)
|
55
51
|
when :map
|
56
52
|
_, key_type, value_type = type
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
to_bytes(raw, value_type, value, 2)
|
63
|
-
end
|
64
|
-
write_bytes(io, raw)
|
65
|
-
else
|
66
|
-
nil_to_bytes(io, size_bytes)
|
53
|
+
raw = ''
|
54
|
+
write_short(raw, value.size)
|
55
|
+
value.each do |key, value|
|
56
|
+
to_bytes(raw, key_type, key, 2)
|
57
|
+
to_bytes(raw, value_type, value, 2)
|
67
58
|
end
|
59
|
+
write_bytes(io, raw)
|
68
60
|
else
|
69
61
|
raise UnsupportedColumnTypeError, %(Unsupported column collection type: #{type.first})
|
70
62
|
end
|
@@ -96,7 +88,7 @@ module Cql
|
|
96
88
|
:varchar => method(:bytes_to_varchar),
|
97
89
|
:text => method(:bytes_to_varchar),
|
98
90
|
:varint => method(:bytes_to_varint),
|
99
|
-
:timeuuid => method(:
|
91
|
+
:timeuuid => method(:bytes_to_timeuuid),
|
100
92
|
:uuid => method(:bytes_to_uuid),
|
101
93
|
:inet => method(:bytes_to_inet),
|
102
94
|
}
|
@@ -108,7 +100,6 @@ module Cql
|
|
108
100
|
:bigint => method(:bigint_to_bytes),
|
109
101
|
:blob => method(:blob_to_bytes),
|
110
102
|
:boolean => method(:boolean_to_bytes),
|
111
|
-
:counter => method(:bigint_to_bytes),
|
112
103
|
:decimal => method(:decimal_to_bytes),
|
113
104
|
:double => method(:double_to_bytes),
|
114
105
|
:float => method(:float_to_bytes),
|
@@ -197,6 +188,11 @@ module Cql
|
|
197
188
|
read_uuid!(buffer)
|
198
189
|
end
|
199
190
|
|
191
|
+
def bytes_to_timeuuid(buffer, size_bytes)
|
192
|
+
return nil unless read_size(buffer, size_bytes)
|
193
|
+
read_uuid!(buffer, TimeUuid)
|
194
|
+
end
|
195
|
+
|
200
196
|
def bytes_to_inet(buffer, size_bytes)
|
201
197
|
size = read_size(buffer, size_bytes)
|
202
198
|
return nil unless size
|
@@ -233,7 +229,7 @@ module Cql
|
|
233
229
|
end
|
234
230
|
|
235
231
|
def ascii_to_bytes(io, value, size_bytes)
|
236
|
-
v = value
|
232
|
+
v = value.encode(::Encoding::ASCII)
|
237
233
|
if size_bytes == 4
|
238
234
|
write_bytes(io, v)
|
239
235
|
else
|
@@ -242,16 +238,16 @@ module Cql
|
|
242
238
|
end
|
243
239
|
|
244
240
|
def bigint_to_bytes(io, value, size_bytes)
|
245
|
-
if
|
246
|
-
|
247
|
-
write_long(io, value)
|
241
|
+
if size_bytes == 4
|
242
|
+
write_int(io, 8)
|
248
243
|
else
|
249
|
-
|
244
|
+
write_short(io, 8)
|
250
245
|
end
|
246
|
+
write_long(io, value)
|
251
247
|
end
|
252
248
|
|
253
249
|
def blob_to_bytes(io, value, size_bytes)
|
254
|
-
v = value
|
250
|
+
v = value.encode(::Encoding::BINARY)
|
255
251
|
if size_bytes == 4
|
256
252
|
write_bytes(io, v)
|
257
253
|
else
|
@@ -260,16 +256,16 @@ module Cql
|
|
260
256
|
end
|
261
257
|
|
262
258
|
def boolean_to_bytes(io, value, size_bytes)
|
263
|
-
if
|
264
|
-
|
265
|
-
io << (value ? Constants::TRUE_BYTE : Constants::FALSE_BYTE)
|
259
|
+
if size_bytes == 4
|
260
|
+
write_int(io, 1)
|
266
261
|
else
|
267
|
-
|
262
|
+
write_short(io, 1)
|
268
263
|
end
|
264
|
+
io << (value ? Constants::TRUE_BYTE : Constants::FALSE_BYTE)
|
269
265
|
end
|
270
266
|
|
271
267
|
def decimal_to_bytes(io, value, size_bytes)
|
272
|
-
raw =
|
268
|
+
raw = write_decimal('', value)
|
273
269
|
if size_bytes == 4
|
274
270
|
write_bytes(io, raw)
|
275
271
|
else
|
@@ -278,43 +274,43 @@ module Cql
|
|
278
274
|
end
|
279
275
|
|
280
276
|
def double_to_bytes(io, value, size_bytes)
|
281
|
-
if
|
282
|
-
|
283
|
-
write_double(io, value)
|
277
|
+
if size_bytes == 4
|
278
|
+
write_int(io, 8)
|
284
279
|
else
|
285
|
-
|
280
|
+
write_short(io, 8)
|
286
281
|
end
|
282
|
+
write_double(io, value)
|
287
283
|
end
|
288
284
|
|
289
285
|
def float_to_bytes(io, value, size_bytes)
|
290
|
-
if
|
291
|
-
|
292
|
-
write_float(io, value)
|
286
|
+
if size_bytes == 4
|
287
|
+
write_int(io, 4)
|
293
288
|
else
|
294
|
-
|
289
|
+
write_short(io, 4)
|
295
290
|
end
|
291
|
+
write_float(io, value)
|
296
292
|
end
|
297
293
|
|
298
294
|
def inet_to_bytes(io, value, size_bytes)
|
299
|
-
if
|
300
|
-
|
301
|
-
io << value.hton
|
295
|
+
if size_bytes == 4
|
296
|
+
write_int(io, value.ipv6? ? 16 : 4)
|
302
297
|
else
|
303
|
-
|
298
|
+
write_short(io, value.ipv6? ? 16 : 4)
|
304
299
|
end
|
300
|
+
io << value.hton
|
305
301
|
end
|
306
302
|
|
307
303
|
def int_to_bytes(io, value, size_bytes)
|
308
|
-
if
|
309
|
-
|
310
|
-
write_int(io, value)
|
304
|
+
if size_bytes == 4
|
305
|
+
write_int(io, 4)
|
311
306
|
else
|
312
|
-
|
307
|
+
write_short(io, 4)
|
313
308
|
end
|
309
|
+
write_int(io, value)
|
314
310
|
end
|
315
311
|
|
316
312
|
def varchar_to_bytes(io, value, size_bytes)
|
317
|
-
v = value
|
313
|
+
v = value.encode(::Encoding::UTF_8)
|
318
314
|
if size_bytes == 4
|
319
315
|
write_bytes(io, v)
|
320
316
|
else
|
@@ -323,48 +319,32 @@ module Cql
|
|
323
319
|
end
|
324
320
|
|
325
321
|
def timestamp_to_bytes(io, value, size_bytes)
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
write_long(io, ms)
|
322
|
+
ms = (value.to_f * 1000).to_i
|
323
|
+
if size_bytes == 4
|
324
|
+
write_int(io, 8)
|
330
325
|
else
|
331
|
-
|
326
|
+
write_short(io, 8)
|
332
327
|
end
|
328
|
+
write_long(io, ms)
|
333
329
|
end
|
334
330
|
|
335
331
|
def uuid_to_bytes(io, value, size_bytes)
|
336
|
-
if
|
337
|
-
|
338
|
-
write_uuid(io, value)
|
332
|
+
if size_bytes == 4
|
333
|
+
write_int(io, 16)
|
339
334
|
else
|
340
|
-
|
335
|
+
write_short(io, 16)
|
341
336
|
end
|
337
|
+
write_uuid(io, value)
|
342
338
|
end
|
343
339
|
|
344
340
|
def varint_to_bytes(io, value, size_bytes)
|
345
|
-
raw =
|
341
|
+
raw = write_varint('', value)
|
346
342
|
if size_bytes == 4
|
347
343
|
write_bytes(io, raw)
|
348
344
|
else
|
349
345
|
write_short_bytes(io, raw)
|
350
346
|
end
|
351
347
|
end
|
352
|
-
|
353
|
-
def size_to_bytes(io, size, size_bytes)
|
354
|
-
if size_bytes == 4
|
355
|
-
write_int(io, size)
|
356
|
-
else
|
357
|
-
write_short(io, size)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
def nil_to_bytes(io, size_bytes)
|
362
|
-
if size_bytes == 4
|
363
|
-
write_int(io, -1)
|
364
|
-
else
|
365
|
-
write_short(io, -1)
|
366
|
-
end
|
367
|
-
end
|
368
348
|
end
|
369
349
|
end
|
370
350
|
end
|