cassandra-cql 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +203 -0
  4. data/README.rdoc +78 -0
  5. data/Rakefile +150 -0
  6. data/cassandra-cql.gemspec +29 -0
  7. data/lib/cassandra-cql.rb +39 -0
  8. data/lib/cassandra-cql/database.rb +107 -0
  9. data/lib/cassandra-cql/result.rb +133 -0
  10. data/lib/cassandra-cql/row.rb +59 -0
  11. data/lib/cassandra-cql/schema.rb +108 -0
  12. data/lib/cassandra-cql/statement.rb +111 -0
  13. data/lib/cassandra-cql/types/abstract_type.rb +47 -0
  14. data/lib/cassandra-cql/types/ascii_type.rb +25 -0
  15. data/lib/cassandra-cql/types/boolean_type.rb +25 -0
  16. data/lib/cassandra-cql/types/bytes_type.rb +21 -0
  17. data/lib/cassandra-cql/types/decimal_type.rb +25 -0
  18. data/lib/cassandra-cql/types/double_type.rb +25 -0
  19. data/lib/cassandra-cql/types/float_type.rb +25 -0
  20. data/lib/cassandra-cql/types/integer_type.rb +27 -0
  21. data/lib/cassandra-cql/types/long_type.rb +27 -0
  22. data/lib/cassandra-cql/types/utf8_type.rb +25 -0
  23. data/lib/cassandra-cql/types/uuid_type.rb +27 -0
  24. data/lib/cassandra-cql/utility.rb +37 -0
  25. data/lib/cassandra-cql/uuid.rb +21 -0
  26. data/lib/cassandra-cql/version.rb +19 -0
  27. data/spec/column_family_spec.rb +105 -0
  28. data/spec/comparator_spec.rb +225 -0
  29. data/spec/conf/0.8/cassandra.in.sh +41 -0
  30. data/spec/conf/0.8/cassandra.yaml +61 -0
  31. data/spec/conf/0.8/log4j-server.properties +40 -0
  32. data/spec/conf/0.8/schema.txt +10 -0
  33. data/spec/conf/1.0/cassandra.in.sh +41 -0
  34. data/spec/conf/1.0/cassandra.yaml +416 -0
  35. data/spec/conf/1.0/log4j-server.properties +40 -0
  36. data/spec/conf/1.0/schema.txt +10 -0
  37. data/spec/result_spec.rb +173 -0
  38. data/spec/row_spec.rb +55 -0
  39. data/spec/rowkey_spec.rb +223 -0
  40. data/spec/schema_spec.rb +51 -0
  41. data/spec/spec_helper.rb +23 -0
  42. data/spec/statement_spec.rb +224 -0
  43. data/spec/utility_spec.rb +26 -0
  44. data/spec/uuid_spec.rb +26 -0
  45. data/spec/validation_spec.rb +250 -0
  46. data/vendor/gen-rb/cassandra.rb +2212 -0
  47. data/vendor/gen-rb/cassandra_constants.rb +10 -0
  48. data/vendor/gen-rb/cassandra_types.rb +854 -0
  49. metadata +171 -0
@@ -0,0 +1,40 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # for production, you should probably set pattern to %c instead of %l.
18
+ # (%l is slower.)
19
+
20
+ # output messages into a rolling log file as well as stdout
21
+ log4j.rootLogger=DEBUG,stdout,R
22
+
23
+ # stdout
24
+ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
25
+ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
26
+ log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n
27
+
28
+ # rolling log file
29
+ log4j.appender.R=org.apache.log4j.RollingFileAppender
30
+ log4j.appender.R.maxFileSize=20MB
31
+ log4j.appender.R.maxBackupIndex=50
32
+ log4j.appender.R.layout=org.apache.log4j.PatternLayout
33
+ log4j.appender.R.layout.ConversionPattern=%5p [%t] %d{ISO8601} %F (line %L) %m%n
34
+ # Edit the next line to point to your logs directory
35
+ log4j.appender.R.File=data/logs/system.log
36
+
37
+ # Application logging options
38
+ #log4j.logger.org.apache.cassandra=DEBUG
39
+ #log4j.logger.org.apache.cassandra.db=DEBUG
40
+ #log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG
@@ -0,0 +1,10 @@
1
+ create keyspace TypeConversions with
2
+ placement_strategy = 'org.apache.cassandra.locator.LocalStrategy' AND
3
+ strategy_options = [{replication_factor:1}];
4
+ use TypeConversions;
5
+ create column family UUIDColumnConversion with comparator = TimeUUIDType;
6
+ create column family SuperUUID with comparator = TimeUUIDType and column_type = Super;
7
+ create column family IntegerConversion with comparator = 'IntegerType';
8
+ create column family LongConversion with comparator = 'LongType';
9
+ create column family CounterConversion with comparator = 'UTF8Type' and
10
+ default_validation_class = CounterColumnType;
@@ -0,0 +1,173 @@
1
+ require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
2
+ include CassandraCQL
3
+
4
+ describe "void results" do
5
+ before(:each) do
6
+ @connection = setup_cassandra_connection
7
+ end
8
+
9
+ it "should return nil" do
10
+ @connection.execute("USE system").should be_nil
11
+ end
12
+ end
13
+
14
+ describe "sparse row results" do
15
+ before(:each) do
16
+ @connection = setup_cassandra_connection
17
+ if !@connection.schema.column_family_names.include?('sparse_results')
18
+ @connection.execute("CREATE COLUMNFAMILY sparse_results (id varchar PRIMARY KEY)")
19
+ else
20
+ @connection.execute("TRUNCATE sparse_results")
21
+ end
22
+ end
23
+
24
+ it "should should be handled properly" do
25
+ @connection.execute("INSERT INTO sparse_results (id, col1, col2, col3) VALUES (?, ?, ?, ?)", 'key1', 'val1', 'val2', 'val3').should be_nil
26
+ @connection.execute("INSERT INTO sparse_results (id, col4, col5, col6) VALUES (?, ?, ?, ?)", 'key2', 'val4', 'val5', 'val6').should be_nil
27
+ result = @connection.execute("SELECT col1, col2, col3, col4 FROM sparse_results")
28
+ result.rows.should eq(2)
29
+ # First column should have 3 columns set, one nil
30
+ row = result.fetch
31
+ row.columns.should eq(4)
32
+ row.column_names.should eq(['col1', 'col2', 'col3', 'col4'])
33
+ row.column_values.should eq(['val1', 'val2', 'val3', nil])
34
+
35
+ # Second column should have the last column set
36
+ row = result.fetch
37
+ row.columns.should eq(4)
38
+ row.column_names.should eq(['col1', 'col2', 'col3', 'col4'])
39
+ row.column_values.should eq([nil, nil, nil, 'val4'])
40
+ end
41
+ end
42
+
43
+ describe "row results" do
44
+ before(:each) do
45
+ @connection = setup_cassandra_connection
46
+ @connection.execute("INSERT INTO sparse_results (id, col1, col2, col3) VALUES (?, ?, ?, ?)", 'key1', 'val1', 'val2', 'val3').should be_nil
47
+ @connection.execute("INSERT INTO sparse_results (id, col4, col5, col6) VALUES (?, ?, ?, ?)", 'key2', 'val4', 'val5', 'val6').should be_nil
48
+ @result = @connection.execute("SELECT col1, col2, col3, col4 FROM sparse_results")
49
+ end
50
+
51
+ it "should return true only for rows?" do
52
+ @result.void?.should be_false
53
+ @result.rows?.should be_true
54
+ @result.int?.should be_false
55
+ end
56
+
57
+ it "should have two rows" do
58
+ @result.rows.should eq(2)
59
+ end
60
+
61
+ context "initialize" do
62
+ it "should have a cursor set to 0" do
63
+ @result.instance_variable_get(:@cursor).should eq(0)
64
+ end
65
+
66
+ it "should have a result" do
67
+ @result.instance_variable_get(:@result).should be_kind_of(CassandraCQL::Thrift::CqlResult)
68
+ end
69
+ end
70
+
71
+ context "setting the cursor" do
72
+ it "should set the cursor" do
73
+ expect {
74
+ @result.cursor = 15
75
+ }.to_not raise_error
76
+ @result.instance_variable_get(:@cursor).should eq(15)
77
+ end
78
+
79
+ it "should not set the cursor" do
80
+ expect {
81
+ @result.cursor = Object
82
+ }.to raise_error(CassandraCQL::Error::InvalidCursor)
83
+ end
84
+ end
85
+
86
+ context "fetching a single row" do
87
+ it "should return a row object twice then nil" do
88
+ @result.fetch_row.should be_kind_of(Row)
89
+ @result.instance_variable_get(:@cursor).should eq(1)
90
+
91
+ @result.fetch_row.should be_kind_of(Row)
92
+ @result.instance_variable_get(:@cursor).should eq(2)
93
+
94
+ @result.fetch_row.should be_nil
95
+ @result.instance_variable_get(:@cursor).should eq(2)
96
+ end
97
+ end
98
+
99
+ context "resetting cursor should fetch the same row" do
100
+ it "should return the same row" do
101
+ @result.instance_variable_get(:@cursor).should eq(0)
102
+ arr = @result.fetch_array
103
+ @result.cursor = 0
104
+ arr.should eq(@result.fetch_array)
105
+ end
106
+ end
107
+
108
+ context "fetch without a block" do
109
+ it "should return a row twice then nil" do
110
+ @result.fetch.should be_kind_of(Row)
111
+ @result.instance_variable_get(:@cursor).should eq(1)
112
+
113
+ @result.fetch.should be_kind_of(Row)
114
+ @result.instance_variable_get(:@cursor).should eq(2)
115
+
116
+ @result.fetch.should be_nil
117
+ @result.instance_variable_get(:@cursor).should eq(2)
118
+ end
119
+ end
120
+
121
+ context "fetch with a block" do
122
+ it "fetched count should equal the number of rows" do
123
+ counter = 0
124
+ @result.fetch do |row|
125
+ counter += 1
126
+ row.should be_kind_of(Row)
127
+ end
128
+ counter.should eq(@result.rows)
129
+ end
130
+ end
131
+
132
+ context "fetch_array without a block" do
133
+ it "should return a row as an array" do
134
+ row = @result.fetch
135
+ @result.cursor = 0
136
+ arr = @result.fetch_array
137
+ arr.should be_kind_of(Array)
138
+ arr.should eq(row.column_values)
139
+ end
140
+ end
141
+
142
+ context "fetch_array_with a block" do
143
+ it "fetched count should equal the number of rows" do
144
+ counter = 0
145
+ @result.fetch_array do |arr|
146
+ counter += 1
147
+ arr.should be_kind_of(Array)
148
+ end
149
+ counter.should eq(@result.rows)
150
+ end
151
+ end
152
+
153
+ context "fetch_hash without a block" do
154
+ it "should return a hash" do
155
+ row = @result.fetch
156
+ @result.cursor = 0
157
+ hash = @result.fetch_hash
158
+ hash.should be_kind_of(Hash)
159
+ hash.should eq(row.to_hash)
160
+ end
161
+ end
162
+
163
+ context "fetch_hash_with a block" do
164
+ it "should iterate rows() times and return hashes" do
165
+ counter = 0
166
+ @result.fetch_hash do |hash|
167
+ counter += 1
168
+ hash.should be_kind_of(Hash)
169
+ end
170
+ counter.should eq(@result.rows)
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,55 @@
1
+ require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
2
+ include CassandraCQL
3
+
4
+
5
+ describe "basic methods" do
6
+ before(:each) do
7
+ @connection = setup_cassandra_connection
8
+ if @connection.schema.column_family_names.include?('basic_methods')
9
+ @connection.execute("DROP COLUMNFAMILY basic_methods")
10
+ end
11
+ @connection.execute("CREATE COLUMNFAMILY basic_methods (id varchar PRIMARY KEY, created_at uuid, default_column varchar, name varchar, serial int)")
12
+
13
+ @connection.execute("INSERT INTO basic_methods (id, created_at, name, serial, default_column) VALUES (?, ?, ?, ?, ?)", 'test', Time.new, 'name', 12345, 'snork')
14
+ @row = @connection.execute("SELECT * FROM basic_methods WHERE id=?", "test").fetch
15
+ end
16
+
17
+ context "column_names" do
18
+ it "should return a list of column names" do
19
+ @row.column_names.sort.should eq(["created_at", "default_column", "id", "name", "serial"].sort)
20
+ end
21
+ end
22
+
23
+ context "column_values" do
24
+ it "should return a list of column values as Ruby objects" do
25
+ @row.column_values.should be_kind_of(Array)
26
+ @row.column_values.size.should eq(@row.column_names.size)
27
+ end
28
+ end
29
+
30
+ context "columns" do
31
+ it "should equal the number of columns" do
32
+ @row.column_names.size.should eq(@row.column_values.size)
33
+ @row.columns.should eq(@row.column_names.size)
34
+ end
35
+ end
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
+ context "checking casting" do
44
+ it "should return column_values for to_a" do
45
+ @row.to_a.should eq(@row.column_values)
46
+ end
47
+
48
+ it "should return a hash for to_hash" do
49
+ h = @row.to_hash
50
+ h.should be_kind_of(Hash)
51
+ h.keys.sort.should eq(@row.column_names.sort)
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,223 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
3
+ include CassandraCQL
4
+
5
+ describe "Validation Roundtrip tests" do
6
+ before(:each) do
7
+ @connection = setup_cassandra_connection
8
+ end
9
+
10
+ def create_and_fetch_column(column_family, row_key)
11
+ @connection.execute("insert into #{column_family} (id, test_column) values (?, ?)", row_key, 'test')
12
+ res = @connection.execute("select * from #{column_family} where id = ?", row_key)
13
+ return res.fetch['id']
14
+ end
15
+
16
+ def create_column_family(name, test_row_key_type)
17
+ if !@connection.schema.column_family_names.include?(name)
18
+ @connection.execute("CREATE COLUMNFAMILY #{name} (id #{test_row_key_type} PRIMARY KEY, test_column text)")
19
+ end
20
+ end
21
+
22
+ context "with ascii row_key_validation" do
23
+ let(:cf_name) { "row_key_validation_cf_ascii" }
24
+ before(:each) { create_column_family(cf_name, 'ascii') }
25
+
26
+ it "should return an ascii string" do
27
+ create_and_fetch_column(cf_name, "test string").should eq("test string")
28
+ end
29
+ end
30
+
31
+ context "with bigint row_key_validation" do
32
+ let(:cf_name) { "row_key_validation_cf_bigint" }
33
+ before(:each) { create_column_family(cf_name, 'bigint') }
34
+
35
+ def test_for_value(value)
36
+ create_and_fetch_column(cf_name, value).should eq(value)
37
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
38
+ end
39
+
40
+ it "should properly convert integer values that fit into 1 byte" do
41
+ test_for_value(1)
42
+ end
43
+ it "should properly convert integer values that fit into 2 bytes" do
44
+ test_for_value(2**8 + 80)
45
+ end
46
+ it "should properly convert integer values that fit into 3 bytes" do
47
+ test_for_value(2**16 + 622)
48
+ end
49
+ it "should properly convert integer values that fit into 4 bytes" do
50
+ test_for_value(2**24 + 45820)
51
+ end
52
+ it "should properly convert integer values that fit into 5 bytes" do
53
+ test_for_value(2**32 + 618387)
54
+ end
55
+ end
56
+
57
+ context "with blob row_key_validation" do
58
+ let(:cf_name) { "row_key_validation_cf_blob" }
59
+ before(:each) { create_column_family(cf_name, 'blob') }
60
+
61
+ it "should return a blob" do
62
+ bytes = "binary\x00"
63
+ bytes = bytes.force_encoding('ASCII-8BIT') if RUBY_VERSION >= "1.9"
64
+ create_and_fetch_column(cf_name, bytes).should eq(bytes)
65
+ end
66
+ end
67
+
68
+ context "with boolean row_key_validation" do
69
+ let(:cf_name) { "row_key_validation_cf_boolean" }
70
+ before(:each) { create_column_family(cf_name, 'boolean') }
71
+
72
+ it "should return true" do
73
+ create_and_fetch_column(cf_name, true).should be_true
74
+ end
75
+
76
+ it "should return false" do
77
+ create_and_fetch_column(cf_name, false).should be_false
78
+ end
79
+ end
80
+
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') }
84
+
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'))
95
+ end
96
+ end
97
+
98
+ context "with double row_key_validation" do
99
+ let(:cf_name) { "row_key_validation_cf_double" }
100
+ before(:each) { create_column_family(cf_name, 'double') }
101
+
102
+ def test_for_value(value)
103
+ create_and_fetch_column(cf_name, value).should be_within(0.1).of(value)
104
+ create_and_fetch_column(cf_name, value*-1).should be_within(0.1).of(value*-1)
105
+ end
106
+
107
+ it "should properly convert some float values" do
108
+ test_for_value(1.125)
109
+ test_for_value(384.125)
110
+ test_for_value(65540.125)
111
+ test_for_value(16777217.125)
112
+ test_for_value(1099511627776.125)
113
+ end
114
+ end
115
+
116
+ context "with float row_key_validation" do
117
+ let(:cf_name) { "row_key_validation_cf_float" }
118
+ before(:each) { create_column_family(cf_name, 'float') }
119
+
120
+ def test_for_value(value)
121
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
122
+ create_and_fetch_column(cf_name, value).should eq(value)
123
+ end
124
+
125
+ it "should properly convert some float values" do
126
+ test_for_value(1.125)
127
+ test_for_value(384.125)
128
+ test_for_value(65540.125)
129
+ end
130
+ end
131
+
132
+ context "with int row_key_validation" do
133
+ let(:cf_name) { "row_key_validation_cf_int" }
134
+ before(:each) { create_column_family(cf_name, 'int') }
135
+
136
+ def test_for_value(value)
137
+ create_and_fetch_column(cf_name, value).should eq(value)
138
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
139
+ end
140
+
141
+ it "should properly convert integer values that fit into 1 byte" do
142
+ test_for_value(1)
143
+ end
144
+ it "should properly convert integer values that fit into 2 bytes" do
145
+ test_for_value(2**8 + 80)
146
+ end
147
+ it "should properly convert integer values that fit into 3 bytes" do
148
+ test_for_value(2**16 + 622)
149
+ end
150
+ it "should properly convert integer values that fit into 4 bytes" do
151
+ test_for_value(2**24 + 45820)
152
+ end
153
+ end
154
+
155
+ context "with text row_key_validation" do
156
+ let(:cf_name) { "row_key_validation_cf_text" }
157
+ before(:each) { create_column_family(cf_name, 'varchar') }
158
+
159
+ it "should return a non-multibyte string" do
160
+ create_and_fetch_column(cf_name, "snark").should eq("snark")
161
+ end
162
+
163
+ it "should return a multibyte string" do
164
+ create_and_fetch_column(cf_name, "snårk").should eq("snårk")
165
+ end
166
+ end
167
+
168
+ context "with timestamp row_key_validation" do
169
+ let(:cf_name) { "row_key_validation_cf_timestamp" }
170
+ before(:each) { create_column_family(cf_name, 'timestamp') }
171
+
172
+ it "should return a timestamp" do
173
+ uuid = UUID.new
174
+ #create_and_fetch_column(cf_name, uuid).should eq(uuid)
175
+ end
176
+ end
177
+
178
+ context "with uuid row_key_validation" do
179
+ let(:cf_name) { "row_key_validation_cf_uuid" }
180
+ before(:each) { create_column_family(cf_name, 'uuid') }
181
+
182
+ it "should return a uuid" do
183
+ uuid = UUID.new
184
+ create_and_fetch_column(cf_name, uuid).should eq(uuid)
185
+ end
186
+ end
187
+
188
+ context "with varchar row_key_validation" do
189
+ let(:cf_name) { "row_key_validation_cf_varchar" }
190
+ before(:each) { create_column_family(cf_name, 'varchar') }
191
+
192
+ it "should return a non-multibyte string" do
193
+ create_and_fetch_column(cf_name, "snark").should eq("snark")
194
+ end
195
+
196
+ it "should return a multibyte string" do
197
+ create_and_fetch_column(cf_name, "snårk").should eq("snårk")
198
+ end
199
+ end
200
+
201
+ context "with varint row_key_validation" do
202
+ let(:cf_name) { "row_key_validation_cf_varint" }
203
+ before(:each) { create_column_family(cf_name, 'varint') }
204
+
205
+ def test_for_value(value)
206
+ create_and_fetch_column(cf_name, value).should eq(value)
207
+ create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
208
+ end
209
+
210
+ it "should properly convert integer values that fit into 1 byte" do
211
+ test_for_value(1)
212
+ end
213
+ it "should properly convert integer values that fit into 2 bytes" do
214
+ test_for_value(2**8 + 80)
215
+ end
216
+ it "should properly convert integer values that fit into 3 bytes" do
217
+ test_for_value(2**16 + 622)
218
+ end
219
+ it "should properly convert integer values that fit into more than 8 bytes" do
220
+ test_for_value(2**256)
221
+ end
222
+ end
223
+ end