hallelujah-cassandra-cql 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.rdoc +71 -0
- data/Rakefile +151 -0
- data/hallelujah-cassandra-cql.gemspec +33 -0
- data/lib/cassandra-cql.rb +49 -0
- data/lib/cassandra-cql/0.8.rb +7 -0
- data/lib/cassandra-cql/0.8/result.rb +23 -0
- data/lib/cassandra-cql/0.8/statement.rb +38 -0
- data/lib/cassandra-cql/1.0.rb +7 -0
- data/lib/cassandra-cql/1.0/result.rb +6 -0
- data/lib/cassandra-cql/1.0/statement.rb +6 -0
- data/lib/cassandra-cql/1.1.rb +7 -0
- data/lib/cassandra-cql/1.1/result.rb +6 -0
- data/lib/cassandra-cql/1.1/statement.rb +6 -0
- data/lib/cassandra-cql/database.rb +127 -0
- data/lib/cassandra-cql/result.rb +133 -0
- data/lib/cassandra-cql/row.rb +54 -0
- data/lib/cassandra-cql/schema.rb +108 -0
- data/lib/cassandra-cql/statement.rb +116 -0
- data/lib/cassandra-cql/types/abstract_type.rb +47 -0
- data/lib/cassandra-cql/types/ascii_type.rb +25 -0
- data/lib/cassandra-cql/types/boolean_type.rb +25 -0
- data/lib/cassandra-cql/types/bytes_type.rb +21 -0
- data/lib/cassandra-cql/types/date_type.rb +25 -0
- data/lib/cassandra-cql/types/decimal_type.rb +25 -0
- data/lib/cassandra-cql/types/double_type.rb +25 -0
- data/lib/cassandra-cql/types/float_type.rb +25 -0
- data/lib/cassandra-cql/types/integer_type.rb +27 -0
- data/lib/cassandra-cql/types/long_type.rb +27 -0
- data/lib/cassandra-cql/types/utf8_type.rb +25 -0
- data/lib/cassandra-cql/types/uuid_type.rb +27 -0
- data/lib/cassandra-cql/utility.rb +37 -0
- data/lib/cassandra-cql/uuid.rb +21 -0
- data/lib/cassandra-cql/version.rb +19 -0
- data/spec/column_family_spec.rb +105 -0
- data/spec/comparator_spec.rb +249 -0
- data/spec/conf/0.8/cassandra.in.sh +41 -0
- data/spec/conf/0.8/cassandra.yaml +61 -0
- data/spec/conf/0.8/log4j-server.properties +40 -0
- data/spec/conf/0.8/schema.txt +10 -0
- data/spec/conf/1.0/cassandra.in.sh +41 -0
- data/spec/conf/1.0/cassandra.yaml +416 -0
- data/spec/conf/1.0/log4j-server.properties +40 -0
- data/spec/conf/1.0/schema.txt +10 -0
- data/spec/conf/1.1/cassandra.in.sh +41 -0
- data/spec/conf/1.1/cassandra.yaml +560 -0
- data/spec/conf/1.1/log4j-server.properties +44 -0
- data/spec/conf/1.1/schema.txt +10 -0
- data/spec/database_spec.rb +25 -0
- data/spec/result_spec.rb +173 -0
- data/spec/row_spec.rb +49 -0
- data/spec/rowkey_spec.rb +233 -0
- data/spec/schema_spec.rb +51 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/statement_spec.rb +226 -0
- data/spec/utility_spec.rb +26 -0
- data/spec/uuid_spec.rb +26 -0
- data/spec/validation_spec.rb +272 -0
- data/vendor/0.8/gen-rb/cassandra.rb +2210 -0
- data/vendor/0.8/gen-rb/cassandra_constants.rb +10 -0
- data/vendor/0.8/gen-rb/cassandra_types.rb +811 -0
- data/vendor/1.0/gen-rb/cassandra.rb +2212 -0
- data/vendor/1.0/gen-rb/cassandra_constants.rb +10 -0
- data/vendor/1.0/gen-rb/cassandra_types.rb +854 -0
- data/vendor/1.1/gen-rb/cassandra.rb +2511 -0
- data/vendor/1.1/gen-rb/cassandra_constants.rb +13 -0
- data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
- metadata +230 -0
data/spec/schema_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
include CassandraCQL
|
3
|
+
|
4
|
+
describe "Schema class" do
|
5
|
+
before(:each) do
|
6
|
+
@connection = setup_cassandra_connection
|
7
|
+
@connection.execute("USE system")
|
8
|
+
end
|
9
|
+
|
10
|
+
context "initialize" do
|
11
|
+
it "should set a thrift schema object" do
|
12
|
+
@connection.schema.schema.should be_kind_of(CassandraCQL::Thrift::KsDef)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set column family hash" do
|
16
|
+
@connection.schema.column_families.should be_kind_of(Hash)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set column family hash" do
|
20
|
+
@connection.schema.column_families.should be_kind_of(Hash)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should method_missing" do
|
25
|
+
expect {
|
26
|
+
@connection.schema.this_method_does_not_exist
|
27
|
+
}.to raise_error NoMethodError
|
28
|
+
end
|
29
|
+
|
30
|
+
context "name" do
|
31
|
+
it "should return keyspace name" do
|
32
|
+
@connection.schema.name.should eq('system')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "to_s" do
|
37
|
+
it "should return keyspace name" do
|
38
|
+
@connection.schema.to_s.should eq(@connection.schema.name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "column_family_names" do
|
43
|
+
it "should return cf_def names" do
|
44
|
+
@connection.schema.column_family_names.sort.should eq(@connection.schema.schema.cf_defs.map(&:name).sort)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be the same as tables" do
|
48
|
+
@connection.schema.column_family_names.should eq(@connection.schema.tables)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
CASSANDRA_VERSION = ENV['CASSANDRA_VERSION'] || '1.0' unless defined?(CASSANDRA_VERSION)
|
5
|
+
|
6
|
+
$LOAD_PATH << "#{File.expand_path(File.dirname(__FILE__))}/../lib"
|
7
|
+
require "cassandra-cql/#{CASSANDRA_VERSION}"
|
8
|
+
|
9
|
+
def yaml_fixture(file)
|
10
|
+
if file.kind_of?(Symbol)
|
11
|
+
file = "#{file}.yaml"
|
12
|
+
elsif file !~ /\.yaml$/
|
13
|
+
file = "#{file}.yaml"
|
14
|
+
end
|
15
|
+
YAML::load_file(File.dirname(__FILE__) + "/fixtures/#{file}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup_cassandra_connection
|
19
|
+
@connection ||= CassandraCQL::Database.new(["127.0.0.1:9160"], {}, :retries => 2, :timeout => 1)
|
20
|
+
if !@connection.keyspaces.map(&:name).include?("CassandraCQLTestKeyspace")
|
21
|
+
@connection.execute("CREATE KEYSPACE CassandraCQLTestKeyspace WITH strategy_class='org.apache.cassandra.locator.SimpleStrategy' AND strategy_options:replication_factor=1")
|
22
|
+
end
|
23
|
+
@connection.execute("USE CassandraCQLTestKeyspace")
|
24
|
+
|
25
|
+
@connection
|
26
|
+
end
|
27
|
+
require 'simplecov'
|
28
|
+
SimpleCov.start do
|
29
|
+
add_filter "/spec/"
|
30
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
include CassandraCQL
|
3
|
+
|
4
|
+
describe "initialize" do
|
5
|
+
it "should set a handle and prepare statement" do
|
6
|
+
statement = "use keyspace1"
|
7
|
+
handle = double("Database")
|
8
|
+
sth = Statement.new(handle, statement)
|
9
|
+
sth.statement.should eq(statement)
|
10
|
+
sth.instance_variable_get("@handle").should eq(handle)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "execute" do
|
15
|
+
context "when performing keyspace operations" do
|
16
|
+
before(:each) do
|
17
|
+
@connection = setup_cassandra_connection
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set keyspace without compression" do
|
21
|
+
@connection.keyspace.should_not eq('system')
|
22
|
+
stmt = @connection.prepare("use system")
|
23
|
+
stmt.execute([], :compression => false).should be_nil
|
24
|
+
@connection.keyspace.should eq('system')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should set keyspace with compression" do
|
28
|
+
@connection.keyspace.should_not eq('system')
|
29
|
+
stmt = @connection.prepare("use system")
|
30
|
+
stmt.execute([], :compression => true).should be_nil
|
31
|
+
@connection.keyspace.should eq('system')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should set keyspace to nil when deleting keyspace" do
|
35
|
+
@connection.execute("DROP KEYSPACE #{@connection.keyspace}").should be_nil
|
36
|
+
@connection.keyspace.should be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when performing void-returning column_family operations" do
|
41
|
+
before(:each) do
|
42
|
+
@connection = setup_cassandra_connection
|
43
|
+
if !@connection.schema.column_family_names.include?('colfam_ops')
|
44
|
+
@connection.execute("CREATE COLUMNFAMILY colfam_ops (id varchar PRIMARY KEY)")
|
45
|
+
else
|
46
|
+
@connection.execute("TRUNCATE colfam_ops")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return nil when inserting" do
|
51
|
+
@connection.execute("INSERT INTO colfam_ops (id, column) VALUES (?, ?)", "key", "value").should be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return nil when updating" do
|
55
|
+
@connection.execute("UPDATE colfam_ops SET column=? WHERE id=?", "value", "key").should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return nil when deleting" do
|
59
|
+
@connection.execute("DELETE FROM colfam_ops WHERE id=?", "key").should be_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "escape" do
|
65
|
+
it "should escape quotes" do
|
66
|
+
Statement.escape(%q{'}).should eq(%q{''})
|
67
|
+
Statement.escape(%q{\'}).should eq(%q{\''})
|
68
|
+
Statement.escape(%q{''}).should eq(%q{''''})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "quote" do
|
73
|
+
context "with a string" do
|
74
|
+
it "should add quotes" do
|
75
|
+
Statement.quote("test").should eq("'test'")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "with an integer" do
|
80
|
+
it "should not add quotes" do
|
81
|
+
Statement.quote(15).should eq(15)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with an array" do
|
86
|
+
it "should return a comma-separated list" do
|
87
|
+
Statement.quote([1, 2, 3]).should eq("1,2,3")
|
88
|
+
Statement.quote(["a", "b''", "c"]).should eq("'a','b''','c'")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with an unsupported object" do
|
93
|
+
it "should raise an exception" do
|
94
|
+
expect {
|
95
|
+
Statement.quote(Time.new)
|
96
|
+
}.to raise_error(CassandraCQL::Error::UnescapableObject)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "cast_to_cql" do
|
102
|
+
context "with a Time object" do
|
103
|
+
it "should return a Time object with the number of microseconds since epoch" do
|
104
|
+
ts = Time.new - 86400 # set it to yesterday just to be sure no defaulting to today misses an error
|
105
|
+
long = Statement.cast_to_cql(ts)
|
106
|
+
long.should be_kind_of(Integer)
|
107
|
+
Time.at(long / 1000.0).to_f.should be_within(0.001).of(ts.to_f)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "with a Date object" do
|
112
|
+
it "should return a corresponding Time object" do
|
113
|
+
date = Date.today << 1
|
114
|
+
str = Statement.cast_to_cql(date)
|
115
|
+
str.should eq(date.strftime('%Y-%m-%d'))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "with a Fixnum object" do
|
120
|
+
it "should return the same object" do
|
121
|
+
Statement.cast_to_cql(15).should eq(15)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "with a UUID object" do
|
126
|
+
it "should return the a guid" do
|
127
|
+
uuid = UUID.new
|
128
|
+
guid = Statement.cast_to_cql(uuid)
|
129
|
+
guid.should eq(uuid.to_guid)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "with a String without quotes" do
|
134
|
+
it "should return a copy of itself" do
|
135
|
+
str = "This is a string"
|
136
|
+
new_str = Statement.cast_to_cql(str)
|
137
|
+
str.should eq(str)
|
138
|
+
new_str.object_id.should_not eq(str.object_id)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "with a String with quotes" do
|
143
|
+
it "should return a quoted version" do
|
144
|
+
str = "This is a ' string"
|
145
|
+
new_str = Statement.cast_to_cql(str)
|
146
|
+
new_str.should_not eq(str)
|
147
|
+
new_str.should eq(Statement.escape(str))
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "with binary data" do
|
152
|
+
it "should return an unpacked version" do
|
153
|
+
bytes = "binary\x00"
|
154
|
+
bytes = bytes.force_encoding('ASCII-8BIT') if RUBY_VERSION >= "1.9"
|
155
|
+
new_data = Statement.cast_to_cql(bytes)
|
156
|
+
new_data.should_not eq(bytes)
|
157
|
+
[new_data].pack('H*').should eq(bytes)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "with an array of Fixnums" do
|
162
|
+
it "should equal itself" do
|
163
|
+
arr = [1, 2, 3]
|
164
|
+
Statement.cast_to_cql(arr).should eq(arr)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "with an array of Strings" do
|
169
|
+
it "should return quoted versions of itself" do
|
170
|
+
arr = ["test", "'"]
|
171
|
+
res = Statement.cast_to_cql(arr)
|
172
|
+
arr.map { |o| Statement.cast_to_cql(o) }.should eq(res)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "sanitize" do
|
178
|
+
context "with no bind vars" do
|
179
|
+
it "should return itself" do
|
180
|
+
Statement.sanitize("use keyspace").should eq("use keyspace")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when expecting bind vars" do
|
185
|
+
it "should raise an exception with bind variable mismatch" do
|
186
|
+
expect {
|
187
|
+
Statement.sanitize("use keyspace ?")
|
188
|
+
}.to raise_error(Error::InvalidBindVariable)
|
189
|
+
|
190
|
+
expect {
|
191
|
+
Statement.sanitize("use keyspace ?", ['too', 'many'])
|
192
|
+
}.to raise_error(Error::InvalidBindVariable)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should not raise an exception with matching bind vars" do
|
196
|
+
expect {
|
197
|
+
Statement.sanitize("use keyspace ?", ["test"]).should eq("use keyspace 'test'")
|
198
|
+
}.to_not raise_error(Error::InvalidBindVariable)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should have bind vars in the right order" do
|
202
|
+
expect {
|
203
|
+
Statement.sanitize("use keyspace ? with randomness (?)", ["test", "stuff"]).should eq("use keyspace 'test' with randomness ('stuff')")
|
204
|
+
}.to_not raise_error(Error::InvalidBindVariable)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should not double-escape the single quotes in your string" do
|
208
|
+
Statement.sanitize(
|
209
|
+
"insert into keyspace (key, ?) values (?)", ["vanilla", %Q{I\'m a string with \'cool\' quotes}]
|
210
|
+
).should eq("insert into keyspace (key, 'vanilla') values ('I''m a string with ''cool'' quotes')")
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should handle numbers and stuff appropriately" do
|
214
|
+
Statement.sanitize(
|
215
|
+
"insert into keyspace (key, ?) values (?)", [488, 60.368]
|
216
|
+
).should eq("insert into keyspace (key, 488) values (60.368)")
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "finish" do
|
223
|
+
it "should just return true .. nothing to clean up yet" do
|
224
|
+
Statement.new(nil, 'whatever').finish.should be_true
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
|
3
|
+
include CassandraCQL
|
4
|
+
|
5
|
+
describe "compress" do
|
6
|
+
it "should return some valid gzipped stuff" do
|
7
|
+
stuff = "This is some stuff"
|
8
|
+
bytes = Utility.compress(stuff)
|
9
|
+
Utility.binary_data?(bytes).should be_true
|
10
|
+
Utility.decompress(bytes).should eq(stuff)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be binary data" do
|
14
|
+
if RUBY_VERSION >= "1.9"
|
15
|
+
Utility.binary_data?("binary\x00".force_encoding('ASCII-8BIT')).should be_true
|
16
|
+
else
|
17
|
+
Utility.binary_data?("binary\x00").should be_true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not be binary data" do
|
22
|
+
Utility.binary_data?("test").should_not be_true
|
23
|
+
Utility.binary_data?("snårk").should_not be_true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
data/spec/uuid_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
include CassandraCQL
|
3
|
+
|
4
|
+
describe "UUID" do
|
5
|
+
it "should respond_to to_guid" do
|
6
|
+
UUID.new.respond_to?(:to_guid)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond_to to_time" do
|
10
|
+
UUID.new.respond_to?(:to_time)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should instantiate from raw bytes" do
|
14
|
+
UUID.new("\252}\303\374\3137\021\340\237\214\251}\315\351 ]")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should instantiate from a Time object" do
|
18
|
+
ts = Time.new
|
19
|
+
UUID.new(ts).to_time.should eq(ts)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should turn have a to_time class method that takes bytes" do
|
23
|
+
UUID.to_time("\252}\303\374\3137\021\340\237\214\251}\315\351 ]").should be_kind_of(Time)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,272 @@
|
|
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, value)
|
11
|
+
@connection.execute("insert into #{column_family} (id, test_column) values (?, ?)", 'test', value)
|
12
|
+
res = @connection.execute("select test_column from #{column_family} where id = ?", 'test')
|
13
|
+
return res.fetch[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_column_family(name, test_column_type, opts="")
|
17
|
+
if !@connection.schema.column_family_names.include?(name)
|
18
|
+
@connection.execute("CREATE COLUMNFAMILY #{name} (id text PRIMARY KEY, test_column #{test_column_type}) #{opts}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with ascii validation" do
|
23
|
+
let(:cf_name) { "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 validation" do
|
32
|
+
let(:cf_name) { "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 validation" do
|
58
|
+
let(:cf_name) { "validation_cf_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
|
64
|
+
|
65
|
+
it "should return a blob" do
|
66
|
+
bytes = "binary\x00"
|
67
|
+
bytes = bytes.force_encoding('ASCII-8BIT') if RUBY_VERSION >= "1.9"
|
68
|
+
create_and_fetch_column(cf_name, bytes).should eq(bytes)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with boolean validation" do
|
73
|
+
let(:cf_name) { "validation_cf_boolean" }
|
74
|
+
before(:each) { create_column_family(cf_name, 'boolean') }
|
75
|
+
|
76
|
+
it "should return true" do
|
77
|
+
create_and_fetch_column(cf_name, true).should be_true
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return false" do
|
81
|
+
create_and_fetch_column(cf_name, false).should be_false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with counter validation" do
|
86
|
+
let(:cf_name) { "validation_cf_counter" }
|
87
|
+
before(:each) {
|
88
|
+
if !@connection.schema.column_family_names.include?(cf_name)
|
89
|
+
@connection.execute("CREATE COLUMNFAMILY #{cf_name} (id text PRIMARY KEY) WITH default_validation=CounterColumnType")
|
90
|
+
end
|
91
|
+
@connection.execute("TRUNCATE #{cf_name}")
|
92
|
+
}
|
93
|
+
|
94
|
+
it "should increment a few times" do
|
95
|
+
10.times do |i|
|
96
|
+
@connection.execute("UPDATE #{cf_name} SET test=test + 1 WHERE id=?", 'test_key')
|
97
|
+
@connection.execute("SELECT test FROM #{cf_name} WHERE id=?", 'test_key').fetch[0].should eq(i+1)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should decrement a few times" do
|
102
|
+
10.times do |i|
|
103
|
+
@connection.execute("UPDATE #{cf_name} SET test=test - 1 WHERE id=?", 'test_key')
|
104
|
+
@connection.execute("SELECT test FROM #{cf_name} WHERE id=?", 'test_key').fetch[0].should eq((i+1)*-1)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
if CASSANDRA_VERSION.to_f >= 1.0
|
110
|
+
context "with decimal validation" do
|
111
|
+
let(:cf_name) { "validation_cf_decimal" }
|
112
|
+
before(:each) { create_column_family(cf_name, 'decimal') }
|
113
|
+
|
114
|
+
def test_for_value(value)
|
115
|
+
create_and_fetch_column(cf_name, value).should eq(value)
|
116
|
+
create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should return a small decimal" do
|
120
|
+
test_for_value(15.333)
|
121
|
+
end
|
122
|
+
it "should return a huge decimal" do
|
123
|
+
test_for_value(BigDecimal.new('129182739481237481341234123411.1029348102934810293481039'))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "with double validation" do
|
129
|
+
let(:cf_name) { "validation_cf_double" }
|
130
|
+
before(:each) { create_column_family(cf_name, 'double') }
|
131
|
+
|
132
|
+
def test_for_value(value)
|
133
|
+
create_and_fetch_column(cf_name, value).should be_within(0.1).of(value)
|
134
|
+
create_and_fetch_column(cf_name, value*-1).should be_within(0.1).of(-1*value)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should properly convert some float values" do
|
138
|
+
test_for_value(1.125)
|
139
|
+
test_for_value(384.125)
|
140
|
+
test_for_value(65540.125)
|
141
|
+
test_for_value(16777217.125)
|
142
|
+
test_for_value(1099511627776.125)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "with float validation" do
|
147
|
+
let(:cf_name) { "validation_cf_float" }
|
148
|
+
before(:each) { create_column_family(cf_name, 'float') }
|
149
|
+
|
150
|
+
def test_for_value(value)
|
151
|
+
create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
|
152
|
+
create_and_fetch_column(cf_name, value).should eq(value)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should properly convert some float values" do
|
156
|
+
test_for_value(1.125)
|
157
|
+
test_for_value(384.125)
|
158
|
+
test_for_value(65540.125)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "with int validation" do
|
163
|
+
let(:cf_name) { "validation_cf_int" }
|
164
|
+
before(:each) { create_column_family(cf_name, 'int') }
|
165
|
+
|
166
|
+
def test_for_value(value)
|
167
|
+
create_and_fetch_column(cf_name, value).should eq(value)
|
168
|
+
create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should properly convert integer values that fit into 1 byte" do
|
172
|
+
test_for_value(1)
|
173
|
+
end
|
174
|
+
it "should properly convert integer values that fit into 2 bytes" do
|
175
|
+
test_for_value(2**8 + 80)
|
176
|
+
end
|
177
|
+
it "should properly convert integer values that fit into 3 bytes" do
|
178
|
+
test_for_value(2**16 + 622)
|
179
|
+
end
|
180
|
+
it "should properly convert integer values that fit into 4 bytes" do
|
181
|
+
test_for_value(2**24 + 45820)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context "with text validation" do
|
186
|
+
let(:cf_name) { "validation_cf_text" }
|
187
|
+
before(:each) { create_column_family(cf_name, 'varchar') }
|
188
|
+
|
189
|
+
it "should return a non-multibyte string" do
|
190
|
+
create_and_fetch_column(cf_name, "snark").should eq("snark")
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should return a multibyte string" do
|
194
|
+
if RUBY_VERSION >= "1.9"
|
195
|
+
create_and_fetch_column(cf_name, "sn\xC3\xA5rk".force_encoding('UTF-8')).should eq("sn\xC3\xA5rk".force_encoding('UTF-8'))
|
196
|
+
else
|
197
|
+
create_and_fetch_column(cf_name, "snårk").should eq("snårk")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "with timestamp validation" do
|
203
|
+
let(:cf_name) { "validation_cf_timestamp" }
|
204
|
+
if CASSANDRA_VERSION.to_f == 0.8
|
205
|
+
before(:each) { create_column_family(cf_name, 'date') }
|
206
|
+
else
|
207
|
+
before(:each) { create_column_family(cf_name, 'timestamp') }
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should return a timestamp" do
|
211
|
+
ts = Time.new
|
212
|
+
res = create_and_fetch_column(cf_name, ts)
|
213
|
+
res.to_f.should be_within(0.001).of(ts.to_f)
|
214
|
+
res.class.should eq(Time)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should return a timestamp given a date" do
|
218
|
+
date = Date.today
|
219
|
+
res = create_and_fetch_column(cf_name, date)
|
220
|
+
[:year, :month, :day].each do |sym|
|
221
|
+
res.send(sym).should eq(date.send(sym))
|
222
|
+
end
|
223
|
+
res.class.should eq(Time)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "with uuid validation" do
|
228
|
+
let(:cf_name) { "validation_cf_uuid" }
|
229
|
+
before(:each) { create_column_family(cf_name, 'uuid') }
|
230
|
+
|
231
|
+
it "should return a uuid" do
|
232
|
+
uuid = UUID.new
|
233
|
+
create_and_fetch_column(cf_name, uuid).should eq(uuid)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context "with varchar validation" do
|
238
|
+
let(:cf_name) { "validation_cf_varchar" }
|
239
|
+
before(:each) { create_column_family(cf_name, 'varchar') }
|
240
|
+
|
241
|
+
it "should return a non-multibyte string" do
|
242
|
+
create_and_fetch_column(cf_name, "snark").should eq("snark")
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should return a multibyte string" do
|
246
|
+
create_and_fetch_column(cf_name, "snårk").should eq("snårk")
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "with varint validation" do
|
251
|
+
let(:cf_name) { "validation_cf_varint" }
|
252
|
+
before(:each) { create_column_family(cf_name, 'varint') }
|
253
|
+
|
254
|
+
def test_for_value(value)
|
255
|
+
create_and_fetch_column(cf_name, value).should eq(value)
|
256
|
+
create_and_fetch_column(cf_name, value*-1).should eq(value*-1)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should properly convert integer values that fit into 1 byte" do
|
260
|
+
test_for_value(1)
|
261
|
+
end
|
262
|
+
it "should properly convert integer values that fit into 2 bytes" do
|
263
|
+
test_for_value(2**8 + 80)
|
264
|
+
end
|
265
|
+
it "should properly convert integer values that fit into 3 bytes" do
|
266
|
+
test_for_value(2**16 + 622)
|
267
|
+
end
|
268
|
+
it "should properly convert integer values that fit into more than 8 bytes" do
|
269
|
+
test_for_value(2**256)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|