cassandra-cql 1.0.1

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 (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