cassandra-driver 3.0.0.rc.2-java → 3.0.2-java
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 +51 -39
- data/lib/cassandra.rb +74 -32
- data/lib/cassandra/auth.rb +3 -1
- data/lib/cassandra/cluster.rb +14 -3
- data/lib/cassandra/cluster/client.rb +98 -62
- data/lib/cassandra/cluster/connector.rb +7 -9
- data/lib/cassandra/cluster/metadata.rb +1 -1
- data/lib/cassandra/cluster/options.rb +19 -7
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +3 -0
- data/lib/cassandra/cluster/schema/fetchers.rb +1 -1
- data/lib/cassandra/custom_data.rb +51 -0
- data/lib/cassandra/driver.rb +23 -20
- data/lib/cassandra/execution/options.rb +1 -1
- data/lib/cassandra/index.rb +22 -8
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +19 -1
- data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +7 -0
- data/lib/cassandra/load_balancing/policies/white_list.rb +7 -0
- data/lib/cassandra/protocol.rb +7 -0
- data/lib/cassandra/protocol/coder.rb +28 -8
- data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -4
- data/lib/cassandra/protocol/cql_protocol_handler.rb +3 -2
- data/lib/cassandra/protocol/requests/batch_request.rb +1 -1
- data/lib/cassandra/protocol/requests/execute_request.rb +1 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -1
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +4 -2
- data/lib/cassandra/protocol/v1.rb +2 -1
- data/lib/cassandra/protocol/v3.rb +2 -1
- data/lib/cassandra/protocol/v4.rb +5 -3
- data/lib/cassandra/result.rb +2 -2
- data/lib/cassandra/session.rb +10 -15
- data/lib/cassandra/statement.rb +5 -0
- data/lib/cassandra/statements/batch.rb +6 -0
- data/lib/cassandra/statements/bound.rb +5 -0
- data/lib/cassandra/statements/prepared.rb +11 -2
- data/lib/cassandra/statements/simple.rb +5 -0
- data/lib/cassandra/statements/void.rb +5 -0
- data/lib/cassandra/table.rb +5 -5
- data/lib/cassandra/timestamp_generator.rb +37 -0
- data/lib/cassandra/timestamp_generator/simple.rb +38 -0
- data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
- data/lib/cassandra/tuple.rb +2 -2
- data/lib/cassandra/types.rb +2 -2
- data/lib/cassandra/util.rb +136 -2
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +8 -4
@@ -134,7 +134,8 @@ module Cassandra
|
|
134
134
|
@connection_options.compressor,
|
135
135
|
@connection_options.heartbeat_interval,
|
136
136
|
@connection_options.idle_timeout,
|
137
|
-
@connection_options.requests_per_connection
|
137
|
+
@connection_options.requests_per_connection,
|
138
|
+
@connection_options.custom_type_handlers)
|
138
139
|
end.flat_map do |connection|
|
139
140
|
# connection is a CqlProtocolHandler
|
140
141
|
f = request_options(connection)
|
@@ -154,7 +155,7 @@ module Cassandra
|
|
154
155
|
supported_cql_versions.first :
|
155
156
|
'3.1.0'
|
156
157
|
|
157
|
-
startup_connection(connection, cql_version, compression)
|
158
|
+
startup_connection(host, connection, cql_version, compression)
|
158
159
|
end
|
159
160
|
f.fallback do |error|
|
160
161
|
case error
|
@@ -200,7 +201,7 @@ module Cassandra
|
|
200
201
|
end
|
201
202
|
end
|
202
203
|
|
203
|
-
def startup_connection(connection, cql_version, compression)
|
204
|
+
def startup_connection(host, connection, cql_version, compression)
|
204
205
|
connection.send_request(Protocol::StartupRequest.new(cql_version, compression),
|
205
206
|
@execution_options.timeout).flat_map do |r|
|
206
207
|
case r
|
@@ -213,12 +214,9 @@ module Cassandra
|
|
213
214
|
Ione::Future.failed(cannot_authenticate_error)
|
214
215
|
end
|
215
216
|
else
|
216
|
-
authenticator = @connection_options.create_authenticator(
|
217
|
-
r.authentication_class)
|
217
|
+
authenticator = @connection_options.create_authenticator(r.authentication_class, host)
|
218
218
|
if authenticator
|
219
|
-
challenge_response_cycle(connection,
|
220
|
-
authenticator,
|
221
|
-
authenticator.initial_response)
|
219
|
+
challenge_response_cycle(connection, authenticator, authenticator.initial_response)
|
222
220
|
else
|
223
221
|
Ione::Future.failed(cannot_authenticate_error)
|
224
222
|
end
|
@@ -283,7 +281,7 @@ module Cassandra
|
|
283
281
|
case r
|
284
282
|
when Protocol::AuthChallengeResponse
|
285
283
|
token = authenticator.challenge_response(r.token)
|
286
|
-
challenge_response_cycle(
|
284
|
+
challenge_response_cycle(connection, authenticator, token)
|
287
285
|
when Protocol::AuthSuccessResponse
|
288
286
|
begin
|
289
287
|
authenticator.authentication_successful(r.token)
|
@@ -24,8 +24,8 @@ module Cassandra
|
|
24
24
|
|
25
25
|
attr_reader :auth_provider, :compressor, :connect_timeout, :credentials,
|
26
26
|
:heartbeat_interval, :idle_timeout, :port, :schema_refresh_delay,
|
27
|
-
:schema_refresh_timeout, :ssl
|
28
|
-
attr_boolean :protocol_negotiable, :synchronize_schema, :
|
27
|
+
:schema_refresh_timeout, :ssl, :custom_type_handlers
|
28
|
+
attr_boolean :protocol_negotiable, :synchronize_schema, :nodelay
|
29
29
|
|
30
30
|
attr_accessor :protocol_version
|
31
31
|
|
@@ -44,9 +44,9 @@ module Cassandra
|
|
44
44
|
synchronize_schema,
|
45
45
|
schema_refresh_delay,
|
46
46
|
schema_refresh_timeout,
|
47
|
-
client_timestamps,
|
48
47
|
nodelay,
|
49
|
-
requests_per_connection
|
48
|
+
requests_per_connection,
|
49
|
+
custom_types)
|
50
50
|
@logger = logger
|
51
51
|
@protocol_version = protocol_version
|
52
52
|
@credentials = credentials
|
@@ -60,8 +60,11 @@ module Cassandra
|
|
60
60
|
@synchronize_schema = synchronize_schema
|
61
61
|
@schema_refresh_delay = schema_refresh_delay
|
62
62
|
@schema_refresh_timeout = schema_refresh_timeout
|
63
|
-
@client_timestamps = client_timestamps
|
64
63
|
@nodelay = nodelay
|
64
|
+
@custom_type_handlers = {}
|
65
|
+
custom_types.each do |type_klass|
|
66
|
+
@custom_type_handlers[type_klass.type] = type_klass
|
67
|
+
end
|
65
68
|
|
66
69
|
@connections_per_local_node = connections_per_local_node
|
67
70
|
@connections_per_remote_node = connections_per_remote_node
|
@@ -80,8 +83,17 @@ module Cassandra
|
|
80
83
|
@compressor && @compressor.algorithm
|
81
84
|
end
|
82
85
|
|
83
|
-
def create_authenticator(authentication_class)
|
84
|
-
|
86
|
+
def create_authenticator(authentication_class, host)
|
87
|
+
if @auth_provider
|
88
|
+
# Auth providers should take an auth-class and host, but they used to not, so for backward compatibility
|
89
|
+
# we figure out if this provider does, and if so send both args, otherwise just send the auth-class.
|
90
|
+
|
91
|
+
if @auth_provider.method(:create_authenticator).arity == 1
|
92
|
+
@auth_provider.create_authenticator(authentication_class)
|
93
|
+
else
|
94
|
+
@auth_provider.create_authenticator(authentication_class, host)
|
95
|
+
end
|
96
|
+
end
|
85
97
|
end
|
86
98
|
|
87
99
|
def connections_per_local_node
|
@@ -72,6 +72,9 @@ module Cassandra
|
|
72
72
|
Cassandra::Types.tuple(*node.children.map { |t| lookup_type(t, types)})
|
73
73
|
when 'empty' then
|
74
74
|
Cassandra::Types.custom('org.apache.cassandra.db.marshal.EmptyType')
|
75
|
+
when /\A'/ then
|
76
|
+
# Custom type.
|
77
|
+
Cassandra::Types.custom(node.name[1..-2])
|
75
78
|
else
|
76
79
|
types.fetch(node.name) do
|
77
80
|
raise IncompleteTypeError, "unable to lookup type #{node.name.inspect}"
|
@@ -836,7 +836,7 @@ module Cassandra
|
|
836
836
|
initial_state = Util.encode_object(
|
837
837
|
Protocol::Coder.read_value_v4(
|
838
838
|
Protocol::CqlByteBuffer.new.append_bytes(aggregate_data['initcond']),
|
839
|
-
state_type))
|
839
|
+
state_type, nil))
|
840
840
|
|
841
841
|
# The state-function takes arguments: first the stype, then the args of the aggregate.
|
842
842
|
state_function = functions.get(aggregate_data['state_func'],
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2016 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
|
+
# Use this module to mark domain object classes as custom type implementations for custom-type
|
20
|
+
# columns in C*. This module has no logic of its own, but indicates that the marked class has
|
21
|
+
# certain methods.
|
22
|
+
# @private
|
23
|
+
module Cassandra::CustomData
|
24
|
+
def self.included base
|
25
|
+
base.send :include, InstanceMethods
|
26
|
+
base.extend ClassMethods
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
# @return [Cassandra::Types::Custom] the custom type that this class represents.
|
31
|
+
def type
|
32
|
+
raise NotImplementedError, "#{self.class} must implement the :type class method"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Deserialize the given data into an instance of this domain object class.
|
36
|
+
# @param data [String] byte-array representation of a column value of this custom type.
|
37
|
+
# @return An instance of the domain object class.
|
38
|
+
# @raise [Cassandra::Errors::DecodingError] upon failure.
|
39
|
+
def deserialize(data)
|
40
|
+
raise NotImplementedError, "#{self.class} must implement the :deserialize class method"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
# Serialize this domain object into a byte array to send to C*.
|
46
|
+
# @return [String] byte-array representation of this domain object.
|
47
|
+
def serialize
|
48
|
+
raise NotImplementedError, "#{self.class} must implement the :serialize instance method"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/cassandra/driver.rb
CHANGED
@@ -92,22 +92,25 @@ module Cassandra
|
|
92
92
|
schema_fetcher)
|
93
93
|
end
|
94
94
|
|
95
|
+
let(:cluster_klass) { Cluster }
|
96
|
+
|
95
97
|
let(:cluster) do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
98
|
+
cluster_klass.new(logger,
|
99
|
+
io_reactor,
|
100
|
+
executor,
|
101
|
+
control_connection,
|
102
|
+
cluster_registry,
|
103
|
+
cluster_schema,
|
104
|
+
cluster_metadata,
|
105
|
+
execution_options,
|
106
|
+
connection_options,
|
107
|
+
load_balancing_policy,
|
108
|
+
reconnection_policy,
|
109
|
+
retry_policy,
|
110
|
+
address_resolution_policy,
|
111
|
+
connector,
|
112
|
+
futures_factory,
|
113
|
+
timestamp_generator)
|
111
114
|
end
|
112
115
|
|
113
116
|
let(:execution_options) do
|
@@ -135,12 +138,13 @@ module Cassandra
|
|
135
138
|
synchronize_schema,
|
136
139
|
schema_refresh_delay,
|
137
140
|
schema_refresh_timeout,
|
138
|
-
client_timestamps,
|
139
141
|
nodelay,
|
140
|
-
requests_per_connection
|
142
|
+
requests_per_connection,
|
143
|
+
custom_types
|
141
144
|
)
|
142
145
|
end
|
143
146
|
|
147
|
+
let(:custom_types) { [] }
|
144
148
|
let(:port) { 9042 }
|
145
149
|
let(:protocol_version) { nil }
|
146
150
|
let(:connect_timeout) { 10 }
|
@@ -165,15 +169,14 @@ module Cassandra
|
|
165
169
|
let(:page_size) { 10000 }
|
166
170
|
let(:heartbeat_interval) { 30 }
|
167
171
|
let(:idle_timeout) { 60 }
|
168
|
-
let(:timeout) {
|
172
|
+
let(:timeout) { 12 }
|
169
173
|
let(:synchronize_schema) { true }
|
170
174
|
let(:schema_refresh_delay) { 1 }
|
171
175
|
let(:schema_refresh_timeout) { 10 }
|
172
176
|
let(:thread_pool_size) { 4 }
|
173
177
|
let(:shuffle_replicas) { true }
|
174
|
-
let(:client_timestamps) { false }
|
175
178
|
let(:nodelay) { true }
|
176
|
-
|
179
|
+
let(:timestamp_generator) { nil }
|
177
180
|
let(:connections_per_local_node) { nil }
|
178
181
|
let(:connections_per_remote_node) { nil }
|
179
182
|
let(:requests_per_connection) { nil }
|
@@ -177,7 +177,7 @@ module Cassandra
|
|
177
177
|
@consistency = consistency || trusted_options.consistency
|
178
178
|
@page_size = page_size || trusted_options.page_size
|
179
179
|
@trace = trace.nil? ? trusted_options.trace? : !!trace
|
180
|
-
@timeout = timeout
|
180
|
+
@timeout = options.key?(:timeout) ? timeout : trusted_options.timeout
|
181
181
|
@serial_consistency = serial_consistency || trusted_options.serial_consistency
|
182
182
|
@arguments = arguments || trusted_options.arguments
|
183
183
|
@type_hints = type_hints || trusted_options.type_hints
|
data/lib/cassandra/index.rb
CHANGED
@@ -39,8 +39,17 @@ module Cassandra
|
|
39
39
|
@table = table
|
40
40
|
@name = name.freeze
|
41
41
|
@kind = kind
|
42
|
-
@target = target.freeze
|
43
42
|
@options = options.freeze
|
43
|
+
|
44
|
+
# Target is a bit tricky; it may be an escaped name or not
|
45
|
+
# depending on C* version. Unify to be unescaped since a user
|
46
|
+
# who wants to know the target would want the bare column name.
|
47
|
+
|
48
|
+
@target = if target[0] == '"'
|
49
|
+
target[1..-2]
|
50
|
+
else
|
51
|
+
target
|
52
|
+
end.freeze
|
44
53
|
end
|
45
54
|
|
46
55
|
# @return [Boolean] whether or not this index uses a custom class.
|
@@ -57,13 +66,18 @@ module Cassandra
|
|
57
66
|
def to_cql
|
58
67
|
keyspace_name = Util.escape_name(@table.keyspace.name)
|
59
68
|
table_name = Util.escape_name(@table.name)
|
60
|
-
index_name = Util.escape_name(name)
|
69
|
+
index_name = Util.escape_name(@name)
|
70
|
+
|
71
|
+
# Target is interesting in that it's not necessarily a column name,
|
72
|
+
# so we can't simply escape it. If it contains a paren, we take it as is,
|
73
|
+
# otherwise assume it's a column name and escape accordingly.
|
74
|
+
escaped_target = @target.include?('(') ? @target : Util.escape_name(@target)
|
61
75
|
|
62
76
|
if custom_index?
|
63
|
-
"CREATE CUSTOM INDEX #{index_name} ON #{keyspace_name}.#{table_name} (#{
|
64
|
-
"USING '#{@options['class_name']}'
|
77
|
+
"CREATE CUSTOM INDEX #{index_name} ON #{keyspace_name}.#{table_name} (#{escaped_target}) " \
|
78
|
+
"USING '#{@options['class_name']}'#{options_cql};"
|
65
79
|
else
|
66
|
-
"CREATE INDEX #{index_name} ON #{keyspace_name}.#{table_name} (#{
|
80
|
+
"CREATE INDEX #{index_name} ON #{keyspace_name}.#{table_name} (#{escaped_target});"
|
67
81
|
end
|
68
82
|
end
|
69
83
|
|
@@ -81,7 +95,7 @@ module Cassandra
|
|
81
95
|
# @private
|
82
96
|
def inspect
|
83
97
|
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
84
|
-
"@name=#{@name}
|
98
|
+
"@name=#{@name.inspect} @table=#{@table.inspect} @kind=#{@kind.inspect} @target=#{@target.inspect}>"
|
85
99
|
end
|
86
100
|
|
87
101
|
private
|
@@ -93,9 +107,9 @@ module Cassandra
|
|
93
107
|
end
|
94
108
|
return '' if filtered_options.empty?
|
95
109
|
|
96
|
-
result = 'WITH OPTIONS = {'
|
110
|
+
result = ' WITH OPTIONS = {'
|
97
111
|
result << filtered_options.map do |key, value|
|
98
|
-
"'#{key}':'#{value}'"
|
112
|
+
"'#{key}': '#{value}'"
|
99
113
|
end.join(', ')
|
100
114
|
result << '}'
|
101
115
|
result
|
@@ -62,7 +62,7 @@ module Cassandra
|
|
62
62
|
include MonitorMixin
|
63
63
|
|
64
64
|
def initialize(datacenter = nil,
|
65
|
-
max_remote_hosts_to_use =
|
65
|
+
max_remote_hosts_to_use = 0,
|
66
66
|
use_remote_hosts_for_local_consistency = false)
|
67
67
|
datacenter &&= String(datacenter)
|
68
68
|
max_remote_hosts_to_use &&= Integer(max_remote_hosts_to_use)
|
@@ -75,6 +75,13 @@ module Cassandra
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
# If use_remote* is true, max_remote* must be > 0
|
79
|
+
if use_remote_hosts_for_local_consistency
|
80
|
+
Util.assert(max_remote_hosts_to_use.nil? || max_remote_hosts_to_use > 0,
|
81
|
+
'max_remote_hosts_to_use must be nil (meaning unlimited) or > 0 when ' \
|
82
|
+
'use_remote_hosts_for_local_consistency is true')
|
83
|
+
end
|
84
|
+
|
78
85
|
@datacenter = datacenter
|
79
86
|
@max_remote = max_remote_hosts_to_use
|
80
87
|
@local = ::Array.new
|
@@ -148,6 +155,17 @@ module Cassandra
|
|
148
155
|
|
149
156
|
Plan.new(local, remote, position)
|
150
157
|
end
|
158
|
+
|
159
|
+
# @private
|
160
|
+
def inspect
|
161
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
162
|
+
"datacenter=#{@datacenter.inspect}, " \
|
163
|
+
"use_remote=#{@use_remote.inspect}, " \
|
164
|
+
"max_remote=#{@max_remote.inspect}, " \
|
165
|
+
"local=#{@local.inspect}, " \
|
166
|
+
"remote=#{@remote.inspect}, " \
|
167
|
+
"position=#{@position.inspect}>"
|
168
|
+
end
|
151
169
|
end
|
152
170
|
end
|
153
171
|
end
|
@@ -128,6 +128,13 @@ module Cassandra
|
|
128
128
|
|
129
129
|
Plan.new(hosts, position)
|
130
130
|
end
|
131
|
+
|
132
|
+
# @private
|
133
|
+
def inspect
|
134
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
135
|
+
"hosts=#{@hosts.inspect}, " \
|
136
|
+
"position=#{@position.inspect}>"
|
137
|
+
end
|
131
138
|
end
|
132
139
|
end
|
133
140
|
end
|
@@ -136,6 +136,13 @@ module Cassandra
|
|
136
136
|
|
137
137
|
Plan.new(replicas, @policy, keyspace, statement, options)
|
138
138
|
end
|
139
|
+
|
140
|
+
# @private
|
141
|
+
def inspect
|
142
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
143
|
+
"policy=#{@policy.inspect}, " \
|
144
|
+
"shuffle=#{@shuffle.inspect}>"
|
145
|
+
end
|
139
146
|
end
|
140
147
|
end
|
141
148
|
end
|
@@ -87,6 +87,13 @@ module Cassandra
|
|
87
87
|
def host_down(host)
|
88
88
|
@policy.host_down(host) if @ips.include?(host.ip)
|
89
89
|
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
def inspect
|
93
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
94
|
+
"policy=#{@policy.inspect}, " \
|
95
|
+
"ips=#{@ips.inspect}>"
|
96
|
+
end
|
90
97
|
end
|
91
98
|
end
|
92
99
|
end
|
data/lib/cassandra/protocol.rb
CHANGED
@@ -28,6 +28,13 @@ module Cassandra
|
|
28
28
|
|
29
29
|
BYTES_FORMAT = 'C*'.freeze
|
30
30
|
TWO_INTS_FORMAT = 'NN'.freeze
|
31
|
+
|
32
|
+
# All of the formats above are big-endian (e.g. network-byte-order). Some payloads (custom types) may have
|
33
|
+
# little-endian components.
|
34
|
+
|
35
|
+
DOUBLE_FORMAT_LE = 'E'.freeze
|
36
|
+
INT_FORMAT_LE = 'V'.freeze
|
37
|
+
SHORT_FORMAT_LE = 'v'.freeze
|
31
38
|
end
|
32
39
|
|
33
40
|
module Constants
|
@@ -97,6 +97,7 @@ module Cassandra
|
|
97
97
|
when :bigint, :counter then write_bigint(buffer, value)
|
98
98
|
when :blob then write_blob(buffer, value)
|
99
99
|
when :boolean then write_boolean(buffer, value)
|
100
|
+
when :custom then write_custom(buffer, value, type)
|
100
101
|
when :decimal then write_decimal(buffer, value)
|
101
102
|
when :double then write_double(buffer, value)
|
102
103
|
when :float then write_float(buffer, value)
|
@@ -221,19 +222,19 @@ module Cassandra
|
|
221
222
|
end
|
222
223
|
end
|
223
224
|
|
224
|
-
def read_values_v4(buffer, column_metadata)
|
225
|
+
def read_values_v4(buffer, column_metadata, custom_type_handlers)
|
225
226
|
::Array.new(buffer.read_int) do |_i|
|
226
227
|
row = ::Hash.new
|
227
228
|
|
228
229
|
column_metadata.each do |(_, _, column, type)|
|
229
|
-
row[column] = read_value_v4(buffer, type)
|
230
|
+
row[column] = read_value_v4(buffer, type, custom_type_handlers)
|
230
231
|
end
|
231
232
|
|
232
233
|
row
|
233
234
|
end
|
234
235
|
end
|
235
236
|
|
236
|
-
def read_value_v4(buffer, type)
|
237
|
+
def read_value_v4(buffer, type, custom_type_handlers)
|
237
238
|
case type.kind
|
238
239
|
when :ascii then read_ascii(buffer)
|
239
240
|
when :bigint, :counter then read_bigint(buffer)
|
@@ -253,11 +254,12 @@ module Cassandra
|
|
253
254
|
when :smallint then read_smallint(buffer)
|
254
255
|
when :time then read_time(buffer)
|
255
256
|
when :date then read_date(buffer)
|
257
|
+
when :custom then read_custom(buffer, type, custom_type_handlers)
|
256
258
|
when :list
|
257
259
|
return nil unless read_size(buffer)
|
258
260
|
|
259
261
|
value_type = type.value_type
|
260
|
-
::Array.new(buffer.read_signed_int) { read_value_v4(buffer, value_type) }
|
262
|
+
::Array.new(buffer.read_signed_int) { read_value_v4(buffer, value_type, custom_type_handlers) }
|
261
263
|
when :map
|
262
264
|
return nil unless read_size(buffer)
|
263
265
|
|
@@ -266,7 +268,7 @@ module Cassandra
|
|
266
268
|
value = ::Hash.new
|
267
269
|
|
268
270
|
buffer.read_signed_int.times do
|
269
|
-
value[read_value_v4(buffer, key_type)] = read_value_v4(buffer, value_type)
|
271
|
+
value[read_value_v4(buffer, key_type, custom_type_handlers)] = read_value_v4(buffer, value_type, custom_type_handlers)
|
270
272
|
end
|
271
273
|
|
272
274
|
value
|
@@ -277,7 +279,7 @@ module Cassandra
|
|
277
279
|
value = ::Set.new
|
278
280
|
|
279
281
|
buffer.read_signed_int.times do
|
280
|
-
value << read_value_v4(buffer, value_type)
|
282
|
+
value << read_value_v4(buffer, value_type, custom_type_handlers)
|
281
283
|
end
|
282
284
|
|
283
285
|
value
|
@@ -295,7 +297,7 @@ module Cassandra
|
|
295
297
|
values[field.name] = if length - buffer.length >= size
|
296
298
|
nil
|
297
299
|
else
|
298
|
-
read_value_v4(buffer, field.type)
|
300
|
+
read_value_v4(buffer, field.type, custom_type_handlers)
|
299
301
|
end
|
300
302
|
end
|
301
303
|
|
@@ -308,7 +310,7 @@ module Cassandra
|
|
308
310
|
|
309
311
|
members.each do |member_type|
|
310
312
|
break if buffer.empty?
|
311
|
-
values << read_value_v4(buffer, member_type)
|
313
|
+
values << read_value_v4(buffer, member_type, custom_type_handlers)
|
312
314
|
end
|
313
315
|
|
314
316
|
values.fill(nil, values.length, (members.length - values.length))
|
@@ -774,6 +776,15 @@ module Cassandra
|
|
774
776
|
read_size(buffer) && buffer.read(1) == Constants::TRUE_BYTE
|
775
777
|
end
|
776
778
|
|
779
|
+
def read_custom(buffer, type, custom_type_handlers)
|
780
|
+
# Lookup the type-name to get the Class that can deserialize buffer data into a custom domain object.
|
781
|
+
unless custom_type_handlers && custom_type_handlers.key?(type)
|
782
|
+
raise Errors::DecodingError, %(Unsupported custom column type: #{type.name})
|
783
|
+
end
|
784
|
+
num_bytes = read_size(buffer)
|
785
|
+
custom_type_handlers[type].deserialize(buffer.read(num_bytes)) if num_bytes && num_bytes > 0
|
786
|
+
end
|
787
|
+
|
777
788
|
def read_decimal(buffer)
|
778
789
|
size = read_size(buffer)
|
779
790
|
size && buffer.read_decimal(size)
|
@@ -860,6 +871,15 @@ module Cassandra
|
|
860
871
|
buffer.append(value ? Constants::TRUE_BYTE : Constants::FALSE_BYTE)
|
861
872
|
end
|
862
873
|
|
874
|
+
def write_custom(buffer, value, type)
|
875
|
+
# Verify that the given type-name matches the value's cql type name.
|
876
|
+
if value.class.type != type
|
877
|
+
raise Errors::EncodingError, "type mismatch: value is a #{value.type} and column is a #{type}"
|
878
|
+
end
|
879
|
+
|
880
|
+
buffer.append_bytes(value.serialize)
|
881
|
+
end
|
882
|
+
|
863
883
|
def write_decimal(buffer, value)
|
864
884
|
buffer.append_bytes(CqlByteBuffer.new.append_decimal(value))
|
865
885
|
end
|