cassandra-cql 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,12 +6,12 @@ require 'rspec/core'
6
6
  require 'rspec/core/rake_task'
7
7
 
8
8
  CassandraBinaries = {
9
- '0.8' => 'http://archive.apache.org/dist/cassandra/0.8.4/apache-cassandra-0.8.4-bin.tar.gz',
10
- '1.0' => 'http://archive.apache.org/dist/cassandra/1.0.1/apache-cassandra-1.0.1-bin.tar.gz',
9
+ '0.8' => 'http://archive.apache.org/dist/cassandra/0.8.8/apache-cassandra-0.8.8-bin.tar.gz',
10
+ '1.0' => 'http://archive.apache.org/dist/cassandra/1.0.5/apache-cassandra-1.0.5-bin.tar.gz',
11
11
  }
12
12
 
13
13
  CASSANDRA_VERSION = ENV['CASSANDRA_VERSION'] || '1.0'
14
- CASSANDRA_HOME = File.dirname(__FILE__) + '/tmp'
14
+ CASSANDRA_HOME = ENV['CASSANDRA_HOME'] || File.dirname(__FILE__) + '/tmp'
15
15
  CASSANDRA_PIDFILE = ENV['CASSANDRA_PIDFILE'] || "#{CASSANDRA_HOME}/cassandra.pid"
16
16
 
17
17
  RSpec::Core::RakeTask.new(:spec) do |spec|
@@ -111,12 +111,12 @@ namespace :cassandra do
111
111
  env = setup_environment
112
112
  sh("kill $(cat #{CASSANDRA_PIDFILE})")
113
113
  end
114
-
114
+
115
115
  desc "Delete all data files in #{CASSANDRA_HOME}"
116
116
  task :clean do
117
117
  sh("rm -rf #{File.join(CASSANDRA_HOME, "cassandra-#{CASSANDRA_VERSION}", 'data')}")
118
118
  end
119
-
119
+
120
120
  end
121
121
 
122
122
  desc "Start Cassandra"
@@ -14,8 +14,13 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  =end
16
16
 
17
- here = File.dirname(__FILE__)
18
- require "#{here}/../vendor/gen-rb/cassandra"
17
+ module CassandraCQL; end;
18
+ unless CassandraCQL.respond_to?(:CASSANDRA_VERSION)
19
+ require "cassandra-cql/1.0"
20
+ end
21
+
22
+ here = File.expand_path(File.dirname(__FILE__))
23
+ require "#{here}/../vendor/#{CassandraCQL.CASSANDRA_VERSION}/gen-rb/cassandra"
19
24
 
20
25
  require 'bigdecimal'
21
26
  require 'date'
@@ -39,3 +44,6 @@ require 'cassandra-cql/schema'
39
44
  require 'cassandra-cql/statement'
40
45
  require 'cassandra-cql/result'
41
46
  require 'cassandra-cql/row'
47
+
48
+ require "cassandra-cql/#{CassandraCQL.CASSANDRA_VERSION}/result"
49
+ require "cassandra-cql/#{CassandraCQL.CASSANDRA_VERSION}/statement"
@@ -0,0 +1,7 @@
1
+ module CassandraCQL
2
+ def self.CASSANDRA_VERSION
3
+ "0.8"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra-cql"
@@ -0,0 +1,23 @@
1
+ module CassandraCQL
2
+ module V08
3
+ class ResultSchema < CassandraCQL::ResultSchema
4
+ def initialize(column_family)
5
+ type_slice = lambda {|type| type[type.rindex('.')+1..-1] }
6
+
7
+ @names = Hash.new(type_slice.call(column_family.comparator_type))
8
+ @values = Hash.new(type_slice.call(column_family.default_validation_class))
9
+ column_family.columns.each_pair do |name, type|
10
+ @values[name] = type_slice.call(type)
11
+ end
12
+ end
13
+ end
14
+
15
+ class Result < CassandraCQL::Result
16
+ def initialize(result, column_family)
17
+ @result = result
18
+ @schema = ResultSchema.new(column_family) if rows?
19
+ @cursor = 0
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ module CassandraCQL
2
+ module V08
3
+ class Statement < CassandraCQL::Statement
4
+ SCHEMA_CHANGE_RE = /\s*(create|drop|alter)\s+(\w+)/i
5
+ COLFAM_RE = /\s*select.*from\s+'?(\w+)/i
6
+
7
+ def execute(bind_vars=[], options={})
8
+ column_family = nil
9
+ if @statement =~ COLFAM_RE
10
+ column_family = @handle.schema.column_families[$1].dup
11
+ end
12
+
13
+ sanitized_query = self.class.sanitize(@statement, bind_vars)
14
+ compression_type = CassandraCQL::Thrift::Compression::NONE
15
+ if options[:compression]
16
+ compression_type = CassandraCQL::Thrift::Compression::GZIP
17
+ sanitized_query = Utility.compress(sanitized_query)
18
+ end
19
+
20
+ res = V08::Result.new(@handle.execute_cql_query(sanitized_query, compression_type), column_family)
21
+
22
+ # Change our keyspace if required
23
+ if @statement =~ KS_CHANGE_RE
24
+ @handle.keyspace = $1
25
+ elsif @statement =~ KS_DROP_RE
26
+ @handle.keyspace = nil
27
+ end
28
+
29
+ # We let ints be fetched for now because they'll probably be deprecated later
30
+ if res.void?
31
+ nil
32
+ else
33
+ res
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ module CassandraCQL
2
+ def self.CASSANDRA_VERSION
3
+ "1.0"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra-cql"
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V10
3
+ class Result < CassandraCQL::Result
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module CassandraCQL
2
+ module V10
3
+ class Statement < CassandraCQL::Statement
4
+ end
5
+ end
6
+ end
@@ -42,6 +42,7 @@ module CassandraCQL
42
42
  obj = self
43
43
  @connection.add_callback(:post_connect) do
44
44
  execute("USE #{@keyspace}")
45
+ @connection.login(@auth_request) if @auth_request
45
46
  end
46
47
  end
47
48
 
@@ -60,12 +61,19 @@ module CassandraCQL
60
61
 
61
62
  def reset!
62
63
  disconnect!
63
- reconnect!
64
+ connect!
64
65
  end
65
66
  alias_method :reconnect!, :reset!
66
67
 
68
+ def statement_class
69
+ return @statement_class if @statement_class
70
+
71
+ version_module = 'V' + CassandraCQL.CASSANDRA_VERSION.gsub('.', '')
72
+ return @statement_class = CassandraCQL.const_get(version_module).const_get(:Statement)
73
+ end
74
+
67
75
  def prepare(statement, options={}, &block)
68
- stmt = Statement.new(self, statement)
76
+ stmt = statement_class.new(self, statement)
69
77
  if block_given?
70
78
  yield stmt
71
79
  else
@@ -74,7 +82,7 @@ module CassandraCQL
74
82
  end
75
83
 
76
84
  def execute(statement, *bind_vars)
77
- result = Statement.new(self, statement).execute(bind_vars)
85
+ result = statement_class.new(self, statement).execute(bind_vars)
78
86
  if block_given?
79
87
  yield result
80
88
  else
@@ -103,5 +111,15 @@ module CassandraCQL
103
111
  # TODO: This should be replaced with a CQL call that doesn't exist yet
104
112
  Schema.new(@connection.describe_keyspace(@keyspace))
105
113
  end
114
+
115
+ def login!(username, password)
116
+ request = CassandraCQL::Thrift::AuthenticationRequest.new
117
+ request.credentials = {'username' => username, 'password' => password}
118
+ ret = @connection.login(request)
119
+ # To avoid a double login on the initial connect, we set
120
+ # @auth_request after the first successful login.
121
+ @auth_request = request
122
+ ret
123
+ end
106
124
  end
107
125
  end
@@ -23,7 +23,6 @@ module CassandraCQL
23
23
  end
24
24
 
25
25
  def [](obj)
26
- # Rows include the row key so we skip the first one
27
26
  column_index = obj.kind_of?(Fixnum) ? obj : column_names.index(obj)
28
27
  return nil if column_index.nil?
29
28
  column_values[column_index]
@@ -51,9 +50,5 @@ module CassandraCQL
51
50
  def to_hash
52
51
  Hash[([column_names, column_values]).transpose]
53
52
  end
54
-
55
- def key
56
- ColumnFamily.cast(@row.key, @schema.values[@row.key])
57
- end
58
53
  end
59
54
  end
@@ -31,18 +31,21 @@ module CassandraCQL
31
31
  @handle = handle
32
32
  prepare(statement)
33
33
  end
34
-
34
+
35
35
  def prepare(statement)
36
36
  @statement = statement
37
37
  end
38
-
38
+
39
39
  def execute(bind_vars=[], options={})
40
+ sanitized_query = self.class.sanitize(@statement, bind_vars)
41
+ compression_type = CassandraCQL::Thrift::Compression::NONE
40
42
  if options[:compression]
41
- res = Result.new(@handle.execute_cql_query(Utility.compress(self.class.sanitize(@statement, bind_vars)), CassandraCQL::Thrift::Compression::GZIP))
42
- else
43
- res = Result.new(@handle.execute_cql_query(self.class.sanitize(@statement, bind_vars), CassandraCQL::Thrift::Compression::NONE))
43
+ compression_type = CassandraCQL::Thrift::Compression::GZIP
44
+ sanitized_query = Utility.compress(sanitized_query)
44
45
  end
45
46
 
47
+ res = Result.new(@handle.execute_cql_query(sanitized_query, compression_type))
48
+
46
49
  # Change our keyspace if required
47
50
  if @statement =~ KS_CHANGE_RE
48
51
  @handle.keyspace = $1
@@ -1,3 +1,19 @@
1
+ =begin
2
+ Copyright 2011 Inside Systems, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
1
17
  module CassandraCQL
2
18
  module Types
3
19
  class DateType < AbstractType
@@ -15,5 +15,5 @@ limitations under the License.
15
15
  =end
16
16
 
17
17
  module CassandraCQL
18
- VERSION = "1.0.2"
18
+ VERSION = "1.0.4"
19
19
  end
@@ -97,23 +97,24 @@ describe "Comparator Roundtrip tests" do
97
97
  end
98
98
  res.class.should eq(Time)
99
99
  end
100
-
101
100
  end
102
101
 
103
- context "with decimal comparator" do
104
- let(:cf_name) { "comparator_cf_decimal" }
105
- before(:each) { create_column_family(cf_name, 'DecimalType') }
102
+ if CASSANDRA_VERSION.to_f >= 1.0
103
+ context "with decimal comparator" do
104
+ let(:cf_name) { "comparator_cf_decimal" }
105
+ before(:each) { create_column_family(cf_name, 'DecimalType') }
106
106
 
107
- def test_for_value(value)
108
- create_and_fetch_column(cf_name, value).should eq(value)
109
- create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
110
- end
111
-
112
- it "should return a small decimal" do
113
- test_for_value(15.333)
114
- end
115
- it "should return a huge decimal" do
116
- test_for_value(BigDecimal.new('129182739481237481341234123411.1029348102934810293481039'))
107
+ def test_for_value(value)
108
+ create_and_fetch_column(cf_name, value).should eq(value)
109
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
110
+ end
111
+
112
+ it "should return a small decimal" do
113
+ test_for_value(15.333)
114
+ end
115
+ it "should return a huge decimal" do
116
+ test_for_value(BigDecimal.new('129182739481237481341234123411.1029348102934810293481039'))
117
+ end
117
118
  end
118
119
  end
119
120
 
@@ -151,26 +152,29 @@ describe "Comparator Roundtrip tests" do
151
152
  end
152
153
  end
153
154
 
154
- context "with int comparator" do
155
- let(:cf_name) { "comparator_cf_int" }
156
- before(:each) { create_column_family(cf_name, 'Int32Type') }
155
+ if CASSANDRA_VERSION.to_f >= 1.0
156
+ #Int32Type was added in 1.0 (CASSANDRA-3031)
157
+ context "with int comparator" do
158
+ let(:cf_name) { "comparator_cf_int" }
159
+ before(:each) { create_column_family(cf_name, 'Int32Type') }
157
160
 
158
- def test_for_value(value)
159
- create_and_fetch_column(cf_name, value).should eq(value)
160
- create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
161
- end
162
-
163
- it "should properly convert integer values that fit into 1 byte" do
164
- test_for_value(1)
165
- end
166
- it "should properly convert integer values that fit into 2 bytes" do
167
- test_for_value(2**8 + 80)
168
- end
169
- it "should properly convert integer values that fit into 3 bytes" do
170
- test_for_value(2**16 + 622)
171
- end
172
- it "should properly convert integer values that fit into 4 bytes" do
173
- test_for_value(2**24 + 45820)
161
+ def test_for_value(value)
162
+ create_and_fetch_column(cf_name, value).should eq(value)
163
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
164
+ end
165
+
166
+ it "should properly convert integer values that fit into 1 byte" do
167
+ test_for_value(1)
168
+ end
169
+ it "should properly convert integer values that fit into 2 bytes" do
170
+ test_for_value(2**8 + 80)
171
+ end
172
+ it "should properly convert integer values that fit into 3 bytes" do
173
+ test_for_value(2**16 + 622)
174
+ end
175
+ it "should properly convert integer values that fit into 4 bytes" do
176
+ test_for_value(2**24 + 45820)
177
+ end
174
178
  end
175
179
  end
176
180
 
@@ -0,0 +1,25 @@
1
+ require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
2
+ include CassandraCQL
3
+
4
+ describe "Database" do
5
+ before do
6
+ @connection = setup_cassandra_connection
7
+ end
8
+
9
+ describe "reset!" do
10
+ it "should create a new connection" do
11
+ @connection.should_receive(:connect!)
12
+ @connection.reset!
13
+ end
14
+ end
15
+
16
+ describe "login!" do
17
+ it "should call login! on connection" do
18
+ creds = { 'username' => 'myuser', 'password' => 'mypass' }
19
+ @connection.connection.should_receive(:login) do |auth|
20
+ auth.credentials.should eq(creds)
21
+ end
22
+ @connection.login!(creds['username'], creds['password'])
23
+ end
24
+ end
25
+ end
@@ -34,12 +34,6 @@ describe "basic methods" do
34
34
  end
35
35
  end
36
36
 
37
- context "key" do
38
- it "should return the cql_result row key" do
39
- @row.key.should eq(@row.row.key)
40
- end
41
- end
42
-
43
37
  context "checking casting" do
44
38
  it "should return column_values for to_a" do
45
39
  @row.to_a.should eq(@row.column_values)
@@ -56,7 +56,11 @@ describe "Validation Roundtrip tests" do
56
56
 
57
57
  context "with blob row_key_validation" do
58
58
  let(:cf_name) { "row_key_validation_cf_blob" }
59
- before(:each) { create_column_family(cf_name, 'blob') }
59
+ if CASSANDRA_VERSION.to_f == 0.8
60
+ before(:each) { create_column_family(cf_name, 'bytea') }
61
+ else
62
+ before(:each) { create_column_family(cf_name, 'blob') }
63
+ end
60
64
 
61
65
  it "should return a blob" do
62
66
  bytes = "binary\x00"
@@ -78,20 +82,22 @@ describe "Validation Roundtrip tests" do
78
82
  end
79
83
  end
80
84
 
81
- context "with decimal row_key_validation" do
82
- let(:cf_name) { "row_key_validation_cf_decimal" }
83
- before(:each) { create_column_family(cf_name, 'decimal') }
85
+ if CASSANDRA_VERSION.to_f >= 1.0
86
+ context "with decimal row_key_validation" do
87
+ let(:cf_name) { "row_key_validation_cf_decimal" }
88
+ before(:each) { create_column_family(cf_name, 'decimal') }
84
89
 
85
- def test_for_value(value)
86
- create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
87
- create_and_fetch_column(cf_name, value).should eq(value)
88
- end
89
-
90
- it "should return a small decimal" do
91
- test_for_value(15.333)
92
- end
93
- it "should return a huge decimal" do
94
- test_for_value(BigDecimal.new('129182739481237481341234123411.1029348102934810293481039'))
90
+ def test_for_value(value)
91
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
92
+ create_and_fetch_column(cf_name, value).should eq(value)
93
+ end
94
+
95
+ it "should return a small decimal" do
96
+ test_for_value(15.333)
97
+ end
98
+ it "should return a huge decimal" do
99
+ test_for_value(BigDecimal.new('129182739481237481341234123411.1029348102934810293481039'))
100
+ end
95
101
  end
96
102
  end
97
103
 
@@ -167,7 +173,11 @@ describe "Validation Roundtrip tests" do
167
173
 
168
174
  context "with timestamp row_key_validation" do
169
175
  let(:cf_name) { "row_key_validation_cf_timestamp" }
170
- before(:each) { create_column_family(cf_name, 'timestamp') }
176
+ if CASSANDRA_VERSION.to_f == 0.8
177
+ before(:each) { create_column_family(cf_name, 'date') }
178
+ else
179
+ before(:each) { create_column_family(cf_name, 'timestamp') }
180
+ end
171
181
 
172
182
  it "should return a timestamp" do
173
183
  uuid = UUID.new