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.
Files changed (50) hide show
  1. data/README.md +4 -9
  2. data/lib/cql.rb +1 -0
  3. data/lib/cql/byte_buffer.rb +23 -7
  4. data/lib/cql/client.rb +11 -6
  5. data/lib/cql/client/asynchronous_client.rb +37 -83
  6. data/lib/cql/client/asynchronous_prepared_statement.rb +10 -4
  7. data/lib/cql/client/column_metadata.rb +16 -0
  8. data/lib/cql/client/request_runner.rb +46 -0
  9. data/lib/cql/future.rb +4 -5
  10. data/lib/cql/io.rb +2 -5
  11. data/lib/cql/io/connection.rb +220 -0
  12. data/lib/cql/io/io_reactor.rb +213 -185
  13. data/lib/cql/protocol.rb +1 -0
  14. data/lib/cql/protocol/cql_protocol_handler.rb +201 -0
  15. data/lib/cql/protocol/decoding.rb +6 -31
  16. data/lib/cql/protocol/encoding.rb +1 -5
  17. data/lib/cql/protocol/request.rb +4 -0
  18. data/lib/cql/protocol/responses/schema_change_result_response.rb +15 -0
  19. data/lib/cql/protocol/type_converter.rb +56 -76
  20. data/lib/cql/time_uuid.rb +104 -0
  21. data/lib/cql/uuid.rb +4 -2
  22. data/lib/cql/version.rb +1 -1
  23. data/spec/cql/client/asynchronous_client_spec.rb +47 -71
  24. data/spec/cql/client/asynchronous_prepared_statement_spec.rb +68 -0
  25. data/spec/cql/client/client_shared.rb +3 -3
  26. data/spec/cql/client/column_metadata_spec.rb +80 -0
  27. data/spec/cql/client/request_runner_spec.rb +120 -0
  28. data/spec/cql/future_spec.rb +26 -11
  29. data/spec/cql/io/connection_spec.rb +460 -0
  30. data/spec/cql/io/io_reactor_spec.rb +212 -265
  31. data/spec/cql/protocol/cql_protocol_handler_spec.rb +216 -0
  32. data/spec/cql/protocol/decoding_spec.rb +9 -28
  33. data/spec/cql/protocol/encoding_spec.rb +0 -5
  34. data/spec/cql/protocol/request_spec.rb +16 -0
  35. data/spec/cql/protocol/response_frame_spec.rb +2 -2
  36. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +70 -0
  37. data/spec/cql/time_uuid_spec.rb +136 -0
  38. data/spec/cql/uuid_spec.rb +1 -5
  39. data/spec/integration/client_spec.rb +34 -38
  40. data/spec/integration/io_spec.rb +283 -0
  41. data/spec/integration/protocol_spec.rb +53 -113
  42. data/spec/integration/regression_spec.rb +124 -0
  43. data/spec/integration/uuid_spec.rb +76 -0
  44. data/spec/spec_helper.rb +12 -9
  45. data/spec/support/fake_io_reactor.rb +52 -21
  46. data/spec/support/fake_server.rb +2 -2
  47. metadata +33 -10
  48. checksums.yaml +0 -15
  49. data/lib/cql/io/node_connection.rb +0 -209
  50. data/spec/cql/protocol/type_converter_spec.rb +0 -52
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe 'Regressions' do
7
+ let :connection_options do
8
+ {:host => ENV['CASSANDRA_HOST'], :credentials => {:username => 'cassandra', :password => 'cassandra'}}
9
+ end
10
+
11
+ let :client do
12
+ Cql::Client.connect(connection_options)
13
+ end
14
+
15
+ before do
16
+ client.execute('DROP KEYSPACE cql_rb_client_spec') rescue nil
17
+ client.execute(%(CREATE KEYSPACE cql_rb_client_spec WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1}))
18
+ client.use('cql_rb_client_spec')
19
+ end
20
+
21
+ after do
22
+ client.execute('DROP KEYSPACE cql_rb_client_spec') rescue nil
23
+ client.close rescue nil
24
+ end
25
+
26
+ context 'with multibyte characters' do
27
+ it 'executes queries with multibyte characters' do
28
+ client.execute(%(CREATE TABLE users (user_id VARCHAR PRIMARY KEY, first VARCHAR, last VARCHAR, age INT)))
29
+ client.execute(%(INSERT INTO users (user_id, first, last, age) VALUES ('test', 'ümlaut', 'test', 1)))
30
+ end
31
+
32
+ it 'executes prepared statements with multibyte characters' do
33
+ client.execute(%(CREATE TABLE users (user_id VARCHAR PRIMARY KEY, first VARCHAR, last VARCHAR, age INT)))
34
+ client.execute("INSERT INTO users (user_id, first, last, age) VALUES ('test', 'ümlaut', 'test', 1)")
35
+ statement = client.prepare('INSERT INTO users (user_id, first, last, age) VALUES (?, ?, ?, ?)')
36
+ statement.execute('test2', 'test2', 'test2', 2)
37
+ statement.execute('test3', 'ümlaut', 'test3', 3)
38
+ end
39
+ end
40
+
41
+ context 'with collections' do
42
+ it 'prepares and executes a statement with an append to a set' do
43
+ client.execute(%(CREATE TABLE users (name VARCHAR PRIMARY KEY, emails SET<VARCHAR>)))
44
+ statement = client.prepare(%(UPDATE users SET emails = emails + ? WHERE name = 'eve'))
45
+ statement.execute(['eve@gmail.com'])
46
+ end
47
+
48
+ it 'prepares and executes a statement with an append to a list' do
49
+ client.execute(%(CREATE TABLE users (name VARCHAR PRIMARY KEY, emails LIST<VARCHAR>)))
50
+ statement = client.prepare(%(UPDATE users SET emails = emails + ? WHERE name = 'eve'))
51
+ statement.execute(['eve@gmail.com', 'eve@yahoo.com'])
52
+ end
53
+
54
+ it 'prepares and executes a statement with an append to a map' do
55
+ client.execute(%(CREATE TABLE users (name VARCHAR PRIMARY KEY, emails MAP<VARCHAR, VARCHAR>)))
56
+ statement = client.prepare(%(UPDATE users SET emails = emails + ? WHERE name = 'eve'))
57
+ statement.execute({'home' => 'eve@yahoo.com'})
58
+ end
59
+
60
+ it 'prepares and executes a statement with a map assignment' do
61
+ client.execute(%(CREATE TABLE users (name VARCHAR PRIMARY KEY, emails MAP<VARCHAR, VARCHAR>)))
62
+ statement = client.prepare(%(UPDATE users SET emails['home'] = ? WHERE name = 'eve'))
63
+ statement.execute('eve@gmail.com')
64
+ end
65
+ end
66
+
67
+ context 'with null values' do
68
+ it 'decodes null counters' do
69
+ client.execute(%<CREATE TABLE counters (id ASCII, counter1 COUNTER, counter2 COUNTER, PRIMARY KEY (id))>)
70
+ client.execute(%<UPDATE counters SET counter1 = counter1 + 1 WHERE id = 'foo'>)
71
+ result = client.execute(%<SELECT counter1, counter2 FROM counters WHERE id = 'foo'>)
72
+ result.first['counter1'].should == 1
73
+ result.first['counter2'].should be_nil
74
+ end
75
+
76
+ it 'decodes null values' do
77
+ client.execute(<<-CQL)
78
+ CREATE TABLE lots_of_types (
79
+ id INT,
80
+ ascii_column ASCII,
81
+ bigint_column BIGINT,
82
+ blob_column BLOB,
83
+ boolean_column BOOLEAN,
84
+ decimal_column DECIMAL,
85
+ double_column DOUBLE,
86
+ float_column FLOAT,
87
+ int_column INT,
88
+ text_column TEXT,
89
+ timestamp_column TIMESTAMP,
90
+ uuid_column UUID,
91
+ varchar_column VARCHAR,
92
+ varint_column VARINT,
93
+ timeuuid_column TIMEUUID,
94
+ inet_column INET,
95
+ list_column LIST<ASCII>,
96
+ map_column MAP<TEXT, BOOLEAN>,
97
+ set_column SET<BLOB>,
98
+ PRIMARY KEY (id)
99
+ )
100
+ CQL
101
+ client.execute(%<INSERT INTO lots_of_types (id) VALUES (3)>)
102
+ result = client.execute(%<SELECT * FROM lots_of_types WHERE id = 3>)
103
+ row = result.first
104
+ row['ascii_column'].should be_nil
105
+ row['bigint_column'].should be_nil
106
+ row['blob_column'].should be_nil
107
+ row['boolean_column'].should be_nil
108
+ row['decimal_column'].should be_nil
109
+ row['double_column'].should be_nil
110
+ row['float_column'].should be_nil
111
+ row['int_column'].should be_nil
112
+ row['text_column'].should be_nil
113
+ row['timestamp_column'].should be_nil
114
+ row['uuid_column'].should be_nil
115
+ row['varchar_column'].should be_nil
116
+ row['varint_column'].should be_nil
117
+ row['timeuuid_column'].should be_nil
118
+ row['inet_column'].should be_nil
119
+ row['list_column'].should be_nil
120
+ row['map_column'].should be_nil
121
+ row['set_column'].should be_nil
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe 'Loading and storing UUIDs' do
7
+ let :connection_options do
8
+ {:host => ENV['CASSANDRA_HOST'], :credentials => {:username => 'cassandra', :password => 'cassandra'}}
9
+ end
10
+
11
+ let :client do
12
+ Cql::Client.connect(connection_options)
13
+ end
14
+
15
+ let :keyspace_name do
16
+ "cql_rb_#{rand(1000)}"
17
+ end
18
+
19
+ before do
20
+ client.connect
21
+ client.execute(%<CREATE KEYSPACE #{keyspace_name} WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}>)
22
+ client.use(keyspace_name)
23
+ end
24
+
25
+ after do
26
+ client.execute(%<DROP KEYSPACE #{keyspace_name}>)
27
+ client.close
28
+ end
29
+
30
+ context Cql::Uuid do
31
+ let :store_statement do
32
+ client.prepare(%<INSERT INTO ids (id, data) VALUES (?, ?)>)
33
+ end
34
+
35
+ before do
36
+ client.execute(%<CREATE TABLE ids (id UUID PRIMARY KEY, data TEXT)>)
37
+ end
38
+
39
+ it 'can be used to store data in UUID cells' do
40
+ store_statement.execute(Cql::Uuid.new('39bc6ab8-d0f5-11e2-b041-adb2253022a3'), 'hello world')
41
+ end
42
+
43
+ it 'will be used when loading data from UUID cells' do
44
+ store_statement.execute(Cql::Uuid.new('39bc6ab8-d0f5-11e2-b041-adb2253022a3'), 'hello world')
45
+ client.execute(%<SELECT * FROM ids>).first['id'].should == Cql::Uuid.new('39bc6ab8-d0f5-11e2-b041-adb2253022a3')
46
+ end
47
+ end
48
+
49
+ context Cql::TimeUuid::Generator do
50
+ let :store_statement do
51
+ client.prepare(%<INSERT INTO timeline (id, time, value) VALUES (?, ?, ?)>)
52
+ end
53
+
54
+ let :generator do
55
+ Cql::TimeUuid::Generator.new
56
+ end
57
+
58
+ before do
59
+ client.execute(%<CREATE TABLE timeline (id ASCII, time TIMEUUID, value INT, PRIMARY KEY (id, time))>)
60
+ end
61
+
62
+ it 'can be used to generate values for TIMEUUID cells' do
63
+ store_statement.execute('foo', generator.next, 1)
64
+ store_statement.execute('foo', generator.next, 2)
65
+ store_statement.execute('foo', generator.next, 3)
66
+ result = client.execute(%<SELECT * FROM timeline WHERE id = 'foo'>)
67
+ result.map { |row| row['value'] }.should == [1, 2, 3]
68
+ end
69
+
70
+ it 'will be used when loading data from TIMEUUID cells' do
71
+ store_statement.execute('foo', generator.next, 1)
72
+ result = client.execute(%<SELECT * FROM timeline WHERE id = 'foo'>)
73
+ result.first['time'].should be_a(Cql::TimeUuid)
74
+ end
75
+ end
76
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,26 +1,29 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'bundler/setup'
4
- require 'simplecov'; SimpleCov.start
5
- require 'cql'
6
-
7
3
  ENV['CASSANDRA_HOST'] ||= '127.0.0.1'
8
4
 
9
5
  require 'bundler/setup'
10
6
 
7
+ require 'support/bytes_helper'
8
+ require 'support/await_helper'
9
+ require 'support/fake_server'
10
+ require 'support/fake_io_reactor'
11
+
11
12
  unless ENV['COVERAGE'] == 'no'
13
+ require 'coveralls'
12
14
  require 'simplecov'
15
+
16
+ if ENV.include?('TRAVIS')
17
+ Coveralls.wear!
18
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
19
+ end
20
+
13
21
  SimpleCov.start do
14
22
  add_group 'Source', 'lib'
15
23
  add_group 'Unit tests', 'spec/cql'
16
24
  add_group 'Integration tests', 'spec/integration'
17
- add_group 'Test support', 'spec/support'
18
25
  end
19
26
  end
20
27
 
21
28
  require 'cql'
22
29
 
23
- require 'support/bytes_helper'
24
- require 'support/await_helper'
25
- require 'support/fake_server'
26
- require 'support/fake_io_reactor'
@@ -8,48 +8,79 @@ class FakeIoReactor
8
8
  @connections = []
9
9
  @queued_responses = Hash.new { |h, k| h[k] = [] }
10
10
  @default_host = nil
11
+ @connection_listeners = []
12
+ @started_future = Cql::Future.new
13
+ @startup_delay = 0
11
14
  end
12
15
 
13
- def queue_response(response, host=nil)
14
- @queued_responses[host] << response
16
+ def startup_delay=(n)
17
+ @startup_delay = n
18
+ end
19
+
20
+ def connect(host, port, timeout)
21
+ connection = FakeConnection.new(host, port, timeout)
22
+ @connections << connection
23
+ @connection_listeners.each do |listener|
24
+ listener.call(connection)
25
+ end
26
+ Cql::Future.completed(connection)
27
+ end
28
+
29
+ def on_connection(&listener)
30
+ @connection_listeners << listener
15
31
  end
16
32
 
17
33
  def start
18
34
  @running = true
19
- @connections = []
20
- @connections.each do |connection|
21
- connection[:future].complete! unless connection[:future].complete?
35
+ Thread.start do
36
+ sleep(@startup_delay)
37
+ @started_future.complete!(self)
22
38
  end
23
- Cql::Future.completed
39
+ @started_future
24
40
  end
25
41
 
26
42
  def stop
27
43
  @running = false
44
+ @connections.each(&:close)
28
45
  Cql::Future.completed
29
46
  end
30
47
 
31
48
  def running?
32
49
  @running
33
50
  end
51
+ end
34
52
 
35
- def add_connection(host, port)
36
- @default_host ||= host
37
- future = Cql::Future.new
38
- connection = {:host => host, :port => port, :future => future, :requests => []}
39
- @connections << connection
40
- future.complete!(connection.object_id) if @running
41
- future
53
+ class FakeConnection
54
+ attr_reader :host, :port, :timeout, :requests, :keyspace
55
+
56
+ def initialize(host, port, timeout)
57
+ @host = host
58
+ @port = port
59
+ @timeout = timeout
60
+ @requests = []
61
+ @responses = []
62
+ @closed = false
63
+ @keyspace = nil
64
+ end
65
+
66
+ def close
67
+ @closed = true
68
+ end
69
+
70
+ def queue_response(response)
71
+ @responses << response
42
72
  end
43
73
 
44
- def queue_request(request, connection_id=nil)
45
- if connection_id
46
- connection = @connections.find { |c| c.object_id == connection_id }
74
+ def send_request(request)
75
+ if @closed
76
+ Cql::Future.failed(Cql::NotConnectedError.new)
47
77
  else
48
- connection = @connections.sample
78
+ @requests << request
79
+ response = @responses.shift
80
+ if response.is_a?(Cql::Protocol::SetKeyspaceResultResponse)
81
+ @keyspace = response.keyspace
82
+ end
83
+ Cql::Future.completed(response)
49
84
  end
50
- connection[:requests] << request
51
- response = @queued_responses[connection[:host]].shift || @queued_responses[nil].shift
52
- @last_used_connection = connection
53
- Cql::Future.completed([response, connection.object_id])
54
85
  end
55
86
  end
@@ -1,9 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class FakeServer
4
- attr_reader :connects, :disconnects
4
+ attr_reader :port, :connects, :disconnects
5
5
 
6
- def initialize(port)
6
+ def initialize(port=(2**15 + rand(2**15)))
7
7
  @port = port
8
8
  @state = {}
9
9
  @lock = Mutex.new
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.1.0.pre0
5
+ prerelease: 6
5
6
  platform: ruby
6
7
  authors:
7
8
  - Theo Hultberg
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-10-14 00:00:00.000000000 Z
12
+ date: 2013-07-04 00:00:00.000000000 Z
12
13
  dependencies: []
13
14
  description: A pure Ruby CQL3 driver for Cassandra
14
15
  email:
@@ -22,14 +23,16 @@ files:
22
23
  - lib/cql/client/asynchronous_prepared_statement.rb
23
24
  - lib/cql/client/column_metadata.rb
24
25
  - lib/cql/client/query_result.rb
26
+ - lib/cql/client/request_runner.rb
25
27
  - lib/cql/client/result_metadata.rb
26
28
  - lib/cql/client/synchronous_client.rb
27
29
  - lib/cql/client/synchronous_prepared_statement.rb
28
30
  - lib/cql/client.rb
29
31
  - lib/cql/future.rb
32
+ - lib/cql/io/connection.rb
30
33
  - lib/cql/io/io_reactor.rb
31
- - lib/cql/io/node_connection.rb
32
34
  - lib/cql/io.rb
35
+ - lib/cql/protocol/cql_protocol_handler.rb
33
36
  - lib/cql/protocol/decoding.rb
34
37
  - lib/cql/protocol/encoding.rb
35
38
  - lib/cql/protocol/request.rb
@@ -59,6 +62,7 @@ files:
59
62
  - lib/cql/protocol/responses/void_result_response.rb
60
63
  - lib/cql/protocol/type_converter.rb
61
64
  - lib/cql/protocol.rb
65
+ - lib/cql/time_uuid.rb
62
66
  - lib/cql/uuid.rb
63
67
  - lib/cql/version.rb
64
68
  - lib/cql.rb
@@ -66,11 +70,16 @@ files:
66
70
  - README.md
67
71
  - spec/cql/byte_buffer_spec.rb
68
72
  - spec/cql/client/asynchronous_client_spec.rb
73
+ - spec/cql/client/asynchronous_prepared_statement_spec.rb
69
74
  - spec/cql/client/client_shared.rb
75
+ - spec/cql/client/column_metadata_spec.rb
76
+ - spec/cql/client/request_runner_spec.rb
70
77
  - spec/cql/client/synchronous_client_spec.rb
71
78
  - spec/cql/client/synchronous_prepared_statement_spec.rb
72
79
  - spec/cql/future_spec.rb
80
+ - spec/cql/io/connection_spec.rb
73
81
  - spec/cql/io/io_reactor_spec.rb
82
+ - spec/cql/protocol/cql_protocol_handler_spec.rb
74
83
  - spec/cql/protocol/decoding_spec.rb
75
84
  - spec/cql/protocol/encoding_spec.rb
76
85
  - spec/cql/protocol/request_spec.rb
@@ -82,10 +91,14 @@ files:
82
91
  - spec/cql/protocol/requests/register_request_spec.rb
83
92
  - spec/cql/protocol/requests/startup_request_spec.rb
84
93
  - spec/cql/protocol/response_frame_spec.rb
85
- - spec/cql/protocol/type_converter_spec.rb
94
+ - spec/cql/protocol/responses/schema_change_result_response_spec.rb
95
+ - spec/cql/time_uuid_spec.rb
86
96
  - spec/cql/uuid_spec.rb
87
97
  - spec/integration/client_spec.rb
98
+ - spec/integration/io_spec.rb
88
99
  - spec/integration/protocol_spec.rb
100
+ - spec/integration/regression_spec.rb
101
+ - spec/integration/uuid_spec.rb
89
102
  - spec/spec_helper.rb
90
103
  - spec/support/await_helper.rb
91
104
  - spec/support/bytes_helper.rb
@@ -94,35 +107,41 @@ files:
94
107
  homepage: http://github.com/iconara/cql-rb
95
108
  licenses:
96
109
  - Apache
97
- metadata: {}
98
110
  post_install_message:
99
111
  rdoc_options: []
100
112
  require_paths:
101
113
  - lib
102
114
  required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
103
116
  requirements:
104
117
  - - ! '>='
105
118
  - !ruby/object:Gem::Version
106
119
  version: 1.9.2
107
120
  required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
108
122
  requirements:
109
- - - ! '>='
123
+ - - ! '>'
110
124
  - !ruby/object:Gem::Version
111
- version: '0'
125
+ version: 1.3.1
112
126
  requirements: []
113
127
  rubyforge_project:
114
- rubygems_version: 2.1.5
128
+ rubygems_version: 1.8.23
115
129
  signing_key:
116
- specification_version: 4
130
+ specification_version: 3
117
131
  summary: Cassandra CQL3 driver
118
132
  test_files:
119
133
  - spec/cql/byte_buffer_spec.rb
120
134
  - spec/cql/client/asynchronous_client_spec.rb
135
+ - spec/cql/client/asynchronous_prepared_statement_spec.rb
121
136
  - spec/cql/client/client_shared.rb
137
+ - spec/cql/client/column_metadata_spec.rb
138
+ - spec/cql/client/request_runner_spec.rb
122
139
  - spec/cql/client/synchronous_client_spec.rb
123
140
  - spec/cql/client/synchronous_prepared_statement_spec.rb
124
141
  - spec/cql/future_spec.rb
142
+ - spec/cql/io/connection_spec.rb
125
143
  - spec/cql/io/io_reactor_spec.rb
144
+ - spec/cql/protocol/cql_protocol_handler_spec.rb
126
145
  - spec/cql/protocol/decoding_spec.rb
127
146
  - spec/cql/protocol/encoding_spec.rb
128
147
  - spec/cql/protocol/request_spec.rb
@@ -134,10 +153,14 @@ test_files:
134
153
  - spec/cql/protocol/requests/register_request_spec.rb
135
154
  - spec/cql/protocol/requests/startup_request_spec.rb
136
155
  - spec/cql/protocol/response_frame_spec.rb
137
- - spec/cql/protocol/type_converter_spec.rb
156
+ - spec/cql/protocol/responses/schema_change_result_response_spec.rb
157
+ - spec/cql/time_uuid_spec.rb
138
158
  - spec/cql/uuid_spec.rb
139
159
  - spec/integration/client_spec.rb
160
+ - spec/integration/io_spec.rb
140
161
  - spec/integration/protocol_spec.rb
162
+ - spec/integration/regression_spec.rb
163
+ - spec/integration/uuid_spec.rb
141
164
  - spec/spec_helper.rb
142
165
  - spec/support/await_helper.rb
143
166
  - spec/support/bytes_helper.rb