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
@@ -66,6 +66,18 @@ module Cql
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
context 'when encoding user defined type values' do
|
70
|
+
it 'encodes a null value' do
|
71
|
+
converter.to_bytes(buffer, [:udt, {'name' => :string, 'shoe_size' => :int}], nil, 4).should eql_bytes("\xff\xff\xff\xff")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when encoding custom values' do
|
76
|
+
it 'encodes a null value' do
|
77
|
+
converter.to_bytes(buffer, [:custom, 'com.example.CustomType'], nil, 4).should eql_bytes("\xff\xff\xff\xff")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
69
81
|
context 'when encoding and decoding negative numbers' do
|
70
82
|
numeric_types.each do |type|
|
71
83
|
it "encodes and decodes a -1 #{type.upcase}" do
|
@@ -19,7 +19,7 @@ describe 'A CQL client' do
|
|
19
19
|
client.close rescue nil
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def create_keyspace
|
23
23
|
begin
|
24
24
|
client.execute(%(DROP KEYSPACE cql_rb_client_spec))
|
25
25
|
rescue Cql::QueryError => e
|
@@ -27,6 +27,10 @@ describe 'A CQL client' do
|
|
27
27
|
end
|
28
28
|
client.execute(%(CREATE KEYSPACE cql_rb_client_spec WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1}))
|
29
29
|
client.use('cql_rb_client_spec')
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_keyspace_and_table
|
33
|
+
create_keyspace
|
30
34
|
client.execute(%(CREATE TABLE users (user_id VARCHAR PRIMARY KEY, first VARCHAR, last VARCHAR, age INT)))
|
31
35
|
client.execute(%(CREATE TABLE counters (id VARCHAR PRIMARY KEY, count COUNTER)))
|
32
36
|
end
|
@@ -108,13 +112,6 @@ describe 'A CQL client' do
|
|
108
112
|
counters = result.each_with_object({}) { |row, acc| acc[row['id']] = row['count'] }
|
109
113
|
counters.should eql('foo' => 11, 'bar' => 3)
|
110
114
|
end
|
111
|
-
|
112
|
-
it 'handles altered tables' do
|
113
|
-
result1 = statement.execute('sue')
|
114
|
-
client.execute('ALTER TABLE users ADD password VARCHAR')
|
115
|
-
result2 = statement.execute('sue')
|
116
|
-
result2.to_a.should eql(result1.to_a)
|
117
|
-
end
|
118
115
|
end
|
119
116
|
|
120
117
|
context 'with multiple connections' do
|
@@ -445,6 +442,61 @@ describe 'A CQL client' do
|
|
445
442
|
end
|
446
443
|
end
|
447
444
|
|
445
|
+
context 'with user defined types' do
|
446
|
+
before do
|
447
|
+
release_version = client.execute('SELECT release_version FROM system.local').first['release_version']
|
448
|
+
pending 'User defined types are not available in C* before 2.1.0' unless release_version[0, 5] >= '2.1.0'
|
449
|
+
create_keyspace
|
450
|
+
client.execute(%(CREATE TYPE address (street TEXT, city TEXT, zip INT)))
|
451
|
+
client.execute(%(CREATE TYPE company (name TEXT, addresses LIST<address>)))
|
452
|
+
client.execute(%(CREATE TABLE users (id VARCHAR PRIMARY KEY, primary_address address, secondary_addresses MAP<TEXT, address>, employers SET<company>)))
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'inserts records into a table with a user defined type' do
|
456
|
+
statement = client.prepare(%(INSERT INTO users (id, primary_address) VALUES (?, ?)))
|
457
|
+
statement.execute('sue', {'street' => '123 Some St.', 'city' => 'Frans Sanisco', 'zip' => 76543})
|
458
|
+
result = client.execute(%(SELECT primary_address.street AS street FROM users WHERE id = 'sue'))
|
459
|
+
result.first['street'].should == '123 Some St.'
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'reads records from a table with a user defined type' do
|
463
|
+
client.execute(%(INSERT INTO users (id, primary_address) VALUES ('sue', {street: '123 Some St.', city: 'Frans Sanisco', zip: 76543})))
|
464
|
+
result = client.execute(%(SELECT primary_address FROM users WHERE id = 'sue'))
|
465
|
+
result.first['primary_address'].should eql('street' => '123 Some St.', 'city' => 'Frans Sanisco', 'zip' => 76543)
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'reads records from a table with a user defined type in a collection' do
|
469
|
+
client.execute(<<-CQL)
|
470
|
+
INSERT INTO users (id, primary_address, secondary_addresses)
|
471
|
+
VALUES (
|
472
|
+
'sue',
|
473
|
+
{street: '123 Some St.', city: 'Frans Sanisco', zip: 76543},
|
474
|
+
{'secret_lair': {street: '4 Some Other St.', city: 'Gos Latos', zip: 87654}}
|
475
|
+
)
|
476
|
+
CQL
|
477
|
+
result = client.execute(%(SELECT secondary_addresses FROM users WHERE id = 'sue'))
|
478
|
+
result.first['secondary_addresses'].should eql('secret_lair' => {'street' => '4 Some Other St.', 'city' => 'Gos Latos', 'zip' => 87654})
|
479
|
+
end
|
480
|
+
|
481
|
+
it 'reads records from a table with user defined types nested in other user defined types, and collections' do
|
482
|
+
client.execute(<<-CQL)
|
483
|
+
INSERT INTO users (id, employers)
|
484
|
+
VALUES (
|
485
|
+
'sue',
|
486
|
+
{
|
487
|
+
{name: 'Acme Corp', addresses: [{street: '1 St.', city: '1 City', zip: 11111}, {street: '2 St.', city: '2 City', zip: 22222}]},
|
488
|
+
{name: 'Foo Inc.', addresses: [{street: '3 St.', city: '3 City', zip: 33333}]}
|
489
|
+
}
|
490
|
+
)
|
491
|
+
CQL
|
492
|
+
result = client.execute(%(SELECT employers FROM users WHERE id = 'sue'))
|
493
|
+
result.first['employers'].should eql(Set.new([
|
494
|
+
{'name' => 'Acme Corp', 'addresses' => [{'street' => '1 St.', 'city' => '1 City', 'zip' => 11111}, {'street' => '2 St.', 'city' => '2 City', 'zip' => 22222}]},
|
495
|
+
{'name' => 'Foo Inc.', 'addresses' => [{'street' => '3 St.', 'city' => '3 City', 'zip' => 33333}]}
|
496
|
+
]))
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
448
500
|
context 'with error conditions' do
|
449
501
|
it 'raises an error for CQL syntax errors' do
|
450
502
|
expect { client.execute('BAD cql') }.to raise_error(Cql::CqlError)
|
@@ -26,13 +26,13 @@ class FakeIoReactor
|
|
26
26
|
@before_startup_handler = handler
|
27
27
|
end
|
28
28
|
|
29
|
-
def connect(host, port,
|
29
|
+
def connect(host, port, options)
|
30
30
|
if host == '0.0.0.0'
|
31
31
|
Cql::Future.failed(Cql::Io::ConnectionError.new('Can\'t connect to 0.0.0.0'))
|
32
32
|
elsif @down_nodes.include?(host)
|
33
33
|
Cql::Future.failed(Cql::Io::ConnectionError.new('Node down'))
|
34
34
|
else
|
35
|
-
connection = FakeConnection.new(host, port,
|
35
|
+
connection = FakeConnection.new(host, port, options)
|
36
36
|
@connections << connection
|
37
37
|
@connection_listeners.each do |listener|
|
38
38
|
listener.call(connection)
|
@@ -71,12 +71,13 @@ class FakeIoReactor
|
|
71
71
|
end
|
72
72
|
|
73
73
|
class FakeConnection
|
74
|
-
attr_reader :host, :port, :timeout, :requests, :keyspace
|
74
|
+
attr_reader :host, :port, :timeout, :options, :requests, :keyspace
|
75
75
|
|
76
|
-
def initialize(host, port,
|
76
|
+
def initialize(host, port, options={}, data={})
|
77
77
|
@host = host
|
78
78
|
@port = port
|
79
|
-
@
|
79
|
+
@options = options || {}
|
80
|
+
@timeout = @options[:timeout]
|
80
81
|
@requests = []
|
81
82
|
@responses = []
|
82
83
|
@closed = false
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cql-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.1.0.pre0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Hultberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ione
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.2.0.pre3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.2.0.pre3
|
27
27
|
description: A pure Ruby CQL3 driver for Cassandra
|
28
28
|
email:
|
29
29
|
- theo@iconara.net
|
@@ -54,10 +54,10 @@ files:
|
|
54
54
|
- lib/cql/compression.rb
|
55
55
|
- lib/cql/compression/lz4_compressor.rb
|
56
56
|
- lib/cql/compression/snappy_compressor.rb
|
57
|
-
- lib/cql/error_codes.rb
|
58
57
|
- lib/cql/protocol.rb
|
59
58
|
- lib/cql/protocol/cql_byte_buffer.rb
|
60
59
|
- lib/cql/protocol/cql_protocol_handler.rb
|
60
|
+
- lib/cql/protocol/custom_type_parser.rb
|
61
61
|
- lib/cql/protocol/frame_decoder.rb
|
62
62
|
- lib/cql/protocol/frame_encoder.rb
|
63
63
|
- lib/cql/protocol/request.rb
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- spec/cql/compression/snappy_compressor_spec.rb
|
112
112
|
- spec/cql/protocol/cql_byte_buffer_spec.rb
|
113
113
|
- spec/cql/protocol/cql_protocol_handler_spec.rb
|
114
|
+
- spec/cql/protocol/custom_type_parser_spec.rb
|
114
115
|
- spec/cql/protocol/frame_decoder_spec.rb
|
115
116
|
- spec/cql/protocol/frame_encoder_spec.rb
|
116
117
|
- spec/cql/protocol/requests/auth_response_request_spec.rb
|
@@ -166,9 +167,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
166
167
|
version: 1.9.3
|
167
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
169
|
requirements:
|
169
|
-
- - "
|
170
|
+
- - ">"
|
170
171
|
- !ruby/object:Gem::Version
|
171
|
-
version:
|
172
|
+
version: 1.3.1
|
172
173
|
requirements: []
|
173
174
|
rubyforge_project:
|
174
175
|
rubygems_version: 2.2.2
|
@@ -194,6 +195,7 @@ test_files:
|
|
194
195
|
- spec/cql/compression/snappy_compressor_spec.rb
|
195
196
|
- spec/cql/protocol/cql_byte_buffer_spec.rb
|
196
197
|
- spec/cql/protocol/cql_protocol_handler_spec.rb
|
198
|
+
- spec/cql/protocol/custom_type_parser_spec.rb
|
197
199
|
- spec/cql/protocol/frame_decoder_spec.rb
|
198
200
|
- spec/cql/protocol/frame_encoder_spec.rb
|
199
201
|
- spec/cql/protocol/requests/auth_response_request_spec.rb
|
data/lib/cql/error_codes.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Cql
|
4
|
-
module ErrorCodes
|
5
|
-
# Something unexpected happened. This indicates a server-side bug.
|
6
|
-
SERVER_ERROR = 0x0000
|
7
|
-
|
8
|
-
# Some client message triggered a protocol violation (for instance a QUERY
|
9
|
-
# message is sent before a STARTUP one has been sent).
|
10
|
-
PROTOCOL_ERROR = 0x000A
|
11
|
-
|
12
|
-
# CREDENTIALS request failed because Cassandra did not accept the provided credentials.
|
13
|
-
BAD_CREDENTIALS = 0x0100
|
14
|
-
|
15
|
-
# Unavailable exception.
|
16
|
-
#
|
17
|
-
# Details:
|
18
|
-
#
|
19
|
-
# * `:cl` - The consistency level of the query having triggered the exception.
|
20
|
-
# * `:required` - An int representing the number of nodes that should be alive to respect `:cl`.
|
21
|
-
# * `:alive` - An int representing the number of replica that were known to be
|
22
|
-
# alive when the request has been processed (since an unavailable
|
23
|
-
# exception has been triggered, there will be `:alive` < `:required`.
|
24
|
-
UNAVAILABLE = 0x1000
|
25
|
-
|
26
|
-
# The request cannot be processed because the coordinator node is overloaded.
|
27
|
-
OVERLOADED = 0x1001
|
28
|
-
|
29
|
-
# The request was a read request but the coordinator node is bootstrapping.
|
30
|
-
IS_BOOTSTRAPPING = 0x1002
|
31
|
-
|
32
|
-
# Error during a truncation error.
|
33
|
-
TRUNCATE_ERROR = 0x1003
|
34
|
-
|
35
|
-
# Timeout exception during a write request.
|
36
|
-
#
|
37
|
-
# Details:
|
38
|
-
#
|
39
|
-
# * `:cl` - The consistency level of the query having triggered the exception.
|
40
|
-
# * `:received` - An int representing the number of nodes having acknowledged the request.
|
41
|
-
# * `:blockfor` - The number of replica whose acknowledgement is required to achieve `:cl`.
|
42
|
-
# * `:write_type` - A string that describe the type of the write that timeouted. The value of that string can be one of:
|
43
|
-
# - `"SIMPLE"`: the write was a non-batched non-counter write.
|
44
|
-
# - `"BATCH"`: the write was a (logged) batch write. If this type is received, it means the batch log
|
45
|
-
# has been successfully written (otherwise a `"BATCH_LOG"` type would have been send instead).
|
46
|
-
# - `"UNLOGGED_BATCH"`: the write was an unlogged batch. Not batch log write has been attempted.
|
47
|
-
# - `"COUNTER"`: the write was a counter write (batched or not).
|
48
|
-
# - `"BATCH_LOG"`: the timeout occured during the write to the batch log when a (logged) batch write was requested.
|
49
|
-
WRITE_TIMEOUT = 0x1100
|
50
|
-
|
51
|
-
# Timeout exception during a read request.
|
52
|
-
#
|
53
|
-
# Details:
|
54
|
-
#
|
55
|
-
# * `:cl` - The consistency level of the query having triggered the exception
|
56
|
-
# * `:received` - An int representing the number of nodes having answered the request.
|
57
|
-
# * `:blockfor` - The number of replica whose response is required to achieve `:cl`.
|
58
|
-
# Please note that it is possible to have `:received` >= `:blockfor` if
|
59
|
-
# `:data_present` is false. And also in the (unlikely) case were `:cl` is
|
60
|
-
# achieved but the coordinator node timeout while waiting for read-repair
|
61
|
-
# acknowledgement.
|
62
|
-
# * `:data_present` - If `true`, it means the replica that was asked for data has not responded.
|
63
|
-
READ_TIMEOUT = 0x1200
|
64
|
-
|
65
|
-
# The submitted query has a syntax error.
|
66
|
-
SYNTAX_ERROR = 0x2000
|
67
|
-
|
68
|
-
# The logged user doesn't have the right to perform the query.
|
69
|
-
UNAUTHORIZED = 0x2100
|
70
|
-
|
71
|
-
# The query is syntactically correct but invalid.
|
72
|
-
INVALID = 0x2200
|
73
|
-
|
74
|
-
# The query is invalid because of some configuration issue.
|
75
|
-
CONFIG_ERROR = 0x2300
|
76
|
-
|
77
|
-
# The query attempted to create a keyspace or a table that was already existing.
|
78
|
-
#
|
79
|
-
# Details:
|
80
|
-
#
|
81
|
-
# * `:ks` - A string representing either the keyspace that already exists, or the
|
82
|
-
# keyspace in which the table that already exists is.
|
83
|
-
# * `:table` - A string representing the name of the table that already exists. If the
|
84
|
-
# query was attempting to create a keyspace, `:table` will be present but
|
85
|
-
# will be the empty string.
|
86
|
-
ALREADY_EXISTS = 0x2400
|
87
|
-
|
88
|
-
# Can be thrown while a prepared statement tries to be executed if the
|
89
|
-
# provide prepared statement ID is not known by this host.
|
90
|
-
#
|
91
|
-
# Details:
|
92
|
-
#
|
93
|
-
# * `:id` - The unknown ID.
|
94
|
-
UNPREPARED = 0x2500
|
95
|
-
end
|
96
|
-
end
|