whi-cassie 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/HISTORY.txt +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +213 -0
- data/Rakefile +18 -0
- data/VERSION +1 -0
- data/lib/cassie/config.rb +62 -0
- data/lib/cassie/model.rb +483 -0
- data/lib/cassie/railtie.rb +20 -0
- data/lib/cassie/schema.rb +129 -0
- data/lib/cassie/testing.rb +46 -0
- data/lib/cassie.rb +317 -0
- data/lib/whi-cassie.rb +1 -0
- data/spec/cassie/config_spec.rb +56 -0
- data/spec/cassie/model_spec.rb +349 -0
- data/spec/cassie_spec.rb +147 -0
- data/spec/models/thing.rb +35 -0
- data/spec/models/type_tester.rb +23 -0
- data/spec/schema/test.cql +6 -0
- data/spec/spec_helper.rb +33 -0
- data/whi-cassie.gemspec +26 -0
- metadata +144 -0
@@ -0,0 +1,349 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Cassie::Model do
|
4
|
+
|
5
|
+
describe "definition" do
|
6
|
+
it "should define the table name" do
|
7
|
+
Cassie::Thing.table_name.should == "things"
|
8
|
+
Cassie::Thing.keyspace.should == "cassie_specs"
|
9
|
+
Cassie::Thing.full_table_name.should == "cassie_specs.things"
|
10
|
+
Cassie::Thing.column_names.should =~ [:owner, :id, :val]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should define the primary key" do
|
14
|
+
Cassie::Thing.primary_key.should == [:owner, :id]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should alias abbreviated column names with human readable names" do
|
18
|
+
m = Cassie::Thing.new
|
19
|
+
m.id = 1
|
20
|
+
m.identifier.should == 1
|
21
|
+
m.identifier = 2
|
22
|
+
m.id.should == 2
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow null values" do
|
26
|
+
Cassie::Thing.create!(:owner => 1, :id => 2)
|
27
|
+
record = Cassie::Thing.find(:owner => 1, :id => 2)
|
28
|
+
record.value.should == nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "create" do
|
33
|
+
it "should create a record" do
|
34
|
+
record = Cassie::Thing.create(:owner => 1, :identifier => 2, :value => 'foo')
|
35
|
+
record.owner.should == 1
|
36
|
+
Cassie::Thing.find(:owner => 1, :identifier => 2).value.should == 'foo'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not save an invalid record" do
|
40
|
+
record = Cassie::Thing.create(:owner => 1, :value => 'foo')
|
41
|
+
record.should_not be_valid
|
42
|
+
Cassie::Thing.count(:owner => 1).should == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should error on an invalid record using the bang version" do
|
46
|
+
lambda{ Cassie::Thing.create!(:owner => 1, :value => 'foo') }.should raise_error(Cassie::RecordInvalid)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "delete_all" do
|
51
|
+
it "should delete all records matching the key" do
|
52
|
+
Cassie::Thing.create(:owner => 1, :id => 2, :val => 'foo')
|
53
|
+
Cassie::Thing.create(:owner => 1, :id => 3, :val => 'bar')
|
54
|
+
Cassie::Thing.count(:owner => 1).should == 2
|
55
|
+
Cassie::Thing.delete_all(:owner => 1, :id => 2)
|
56
|
+
Cassie::Thing.count(:owner => 1).should == 1
|
57
|
+
Cassie::Thing.find(:owner => 1, :id => 2).should == nil
|
58
|
+
Cassie::Thing.find(:owner => 1, :id => 3).should_not == nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "finding" do
|
63
|
+
let!(:r1){ Cassie::Thing.create(:owner => 1, :id => 2, :val => 'foo') }
|
64
|
+
let!(:r2){ Cassie::Thing.create(:owner => 1, :id => 3, :val => 'bar') }
|
65
|
+
let!(:r3){ Cassie::Thing.create(:owner => 2, :id => 3, :val => 'blah') }
|
66
|
+
|
67
|
+
it "should find all records using a variety of syntaxes" do
|
68
|
+
Cassie::Thing.find_all(where: {:owner => 1}, order: "id ASC").should == [r1, r2]
|
69
|
+
Cassie::Thing.find_all(where: {:owner => 1}, order: "id DESC").should == [r2, r1]
|
70
|
+
Cassie::Thing.find_all(where: {:owner => 1}, order: "id ASC", limit: 1).should == [r1]
|
71
|
+
Cassie::Thing.find_all(where: "owner = 1", order: "id ASC").should == [r1, r2]
|
72
|
+
Cassie::Thing.find_all(where: ["owner = ?", 1], order: "id ASC").should == [r1, r2]
|
73
|
+
Cassie::Thing.find_all(where: {:owner => 0}, order: "id ASC").should == []
|
74
|
+
Cassie::Thing.find_all(where: {:owner => 1, :id => 2}).should == [r1]
|
75
|
+
Cassie::Thing.find_all(where: {:owner => [1, 2]}).should =~ [r1, r2, r3]
|
76
|
+
Cassie::Thing.find_all(where: {:owner => [1, 2]}, options: {:page_size => 1}).should =~ [r1, r2, r3]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should find one record" do
|
80
|
+
Cassie::Thing.find(:owner => 1, :id => 2).should == r1
|
81
|
+
Cassie::Thing.find(:owner => 1, :id => 3).should == r2
|
82
|
+
Cassie::Thing.find(:owner => 1, :id => 0).should == nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should raise an error if the record can't be found and called as find!" do
|
86
|
+
Cassie::Thing.find!(:owner => 1, :id => 2).should == r1
|
87
|
+
lambda{ Cassie::Thing.find!(:owner => 1, :id => 0) }.should raise_error(Cassie::RecordNotFound)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should mark found records as persisted" do
|
91
|
+
Cassie::Thing.find(:owner => 1, :id => 2).persisted?.should == true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should count records" do
|
95
|
+
Cassie::Thing.count(:owner => 1).should == 2
|
96
|
+
Cassie::Thing.count(:owner => 1, :id => 2).should == 1
|
97
|
+
end
|
98
|
+
|
99
|
+
it "won't find all records with a blank where clause" do
|
100
|
+
expect{ Cassie::Thing.find_all(where: {}) }.to raise_error
|
101
|
+
Cassie::Thing.find_all(where: :all).size.should == 3
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "offset_to_id" do
|
106
|
+
let!(:r1){ Cassie::Thing.create(:owner => 1, :id => 2, :val => 'foo') }
|
107
|
+
let!(:r2){ Cassie::Thing.create(:owner => 1, :id => 3, :val => 'bar') }
|
108
|
+
let!(:r3){ Cassie::Thing.create(:owner => 1, :id => 4, :val => 'blah') }
|
109
|
+
let!(:r4){ Cassie::Thing.create(:owner => 1, :id => 5, :val => 'mip') }
|
110
|
+
let!(:r5){ Cassie::Thing.create(:owner => 2, :id => 2, :val => 'grl') }
|
111
|
+
|
112
|
+
it "should calculate the ordering key at a specified offset" do
|
113
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 2).should == 3
|
114
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 2, order: :asc).should == 4
|
115
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 2, batch_size: 1).should == 3
|
116
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 3, batch_size: 1).should == 2
|
117
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 4, batch_size: 1).should == nil
|
118
|
+
Cassie::Thing.offset_to_id({:owner => 1}, 4, batch_size: 100).should == nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "batch" do
|
123
|
+
it "should delegate to Cassie.batch" do
|
124
|
+
Cassie::Thing.connection.should be_a(Cassie)
|
125
|
+
expect(Cassie::Thing.connection).to receive(:batch).and_call_original
|
126
|
+
Cassie::Thing.batch{}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "attributes" do
|
131
|
+
it "should get and set attributes" do
|
132
|
+
record = Cassie::Thing.new(:owner => 1, :id => 2, :val => 'foo')
|
133
|
+
record.attributes.should == {:owner => 1, :id => 2, :val => 'foo'}
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should get and set attributes using human readable names" do
|
137
|
+
record = Cassie::Thing.new(:owner => 1, :identifier => 2, :value => 'foo')
|
138
|
+
record.attributes.should == {:owner => 1, :id => 2, :val => 'foo'}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "save" do
|
143
|
+
it "should not save an invalid record" do
|
144
|
+
record = Cassie::Thing.new(:owner => 1, :val => 'foo')
|
145
|
+
record.save.should == false
|
146
|
+
Cassie::Thing.count(:owner => 1).should == 0
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should raise an error on the bang version on an invalid record" do
|
150
|
+
record = Cassie::Thing.new(:owner => 1, :val => 'foo')
|
151
|
+
lambda{ record.save! }.should raise_error(Cassie::RecordInvalid)
|
152
|
+
Cassie::Thing.count(:owner => 1).should == 0
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should save new records and invoke the create callbacks" do
|
156
|
+
record = Cassie::Thing.new(:owner => 1, :id => 2, :val => 'foo')
|
157
|
+
record.persisted?.should == false
|
158
|
+
record.save.should == true
|
159
|
+
record.persisted?.should == true
|
160
|
+
record.callbacks.should == [:save, :create]
|
161
|
+
Cassie::Thing.find(:owner => 1, :id => 2).should == record
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should save existing records and invoke the update callbacks" do
|
165
|
+
Cassie::Thing.create(:owner => 1, :id => 2, :val => 'foo')
|
166
|
+
record = Cassie::Thing.find(:owner => 1, :id => 2)
|
167
|
+
record.persisted?.should == true
|
168
|
+
record.value = 'bar'
|
169
|
+
record.save.should == true
|
170
|
+
record.persisted?.should == true
|
171
|
+
record.callbacks.should == [:save, :update]
|
172
|
+
Cassie::Thing.find(:owner => 1, :id => 2).value.should == 'bar'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "destroy" do
|
177
|
+
it "should delete a record from Cassandra calling any destroy callbacks" do
|
178
|
+
Cassie::Thing.create(:owner => 1, :id => 2, :val => 'foo')
|
179
|
+
record = Cassie::Thing.find(:owner => 1, :id => 2)
|
180
|
+
record.destroy
|
181
|
+
Cassie::Thing.find(:owner => 1, :id => 2).should == nil
|
182
|
+
record.callbacks.should =~ [:destroy]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "type conversion" do
|
187
|
+
let(:model){ Cassie::TypeTester.new }
|
188
|
+
|
189
|
+
it "should work with varchar columns" do
|
190
|
+
model.varchar = "foo"
|
191
|
+
model.varchar.should == "foo"
|
192
|
+
model.varchar = nil
|
193
|
+
model.varchar.should == nil
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should work with ascii columns" do
|
197
|
+
model.ascii = "foo"
|
198
|
+
model.ascii.should == "foo"
|
199
|
+
model.ascii = nil
|
200
|
+
model.ascii.should == nil
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should work with text columns" do
|
204
|
+
model.text = "foo"
|
205
|
+
model.text.should == "foo"
|
206
|
+
model.text = nil
|
207
|
+
model.text.should == nil
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should work with blob columns" do
|
211
|
+
model.blob = "foo"
|
212
|
+
model.blob.should == "foo"
|
213
|
+
model.blob = nil
|
214
|
+
model.blob.should == nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should work with int columns" do
|
218
|
+
model.int = "1"
|
219
|
+
model.int.should == 1
|
220
|
+
model.int = 2
|
221
|
+
model.int.should == 2
|
222
|
+
model.int = nil
|
223
|
+
model.int.should == nil
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should work with bigint columns" do
|
227
|
+
model.bigint = "1"
|
228
|
+
model.bigint.should == 1
|
229
|
+
model.bigint = 2
|
230
|
+
model.bigint.should == 2
|
231
|
+
model.bigint = nil
|
232
|
+
model.bigint.should == nil
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should work with varint columns" do
|
236
|
+
model.varint = "1"
|
237
|
+
model.varint.should == 1
|
238
|
+
model.varint = 2
|
239
|
+
model.varint.should == 2
|
240
|
+
model.varint = nil
|
241
|
+
model.varint.should == nil
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should work with counter columns" do
|
245
|
+
model.counter = "1"
|
246
|
+
model.counter.should == 1
|
247
|
+
model.counter = 2
|
248
|
+
model.counter.should == 2
|
249
|
+
model.counter = nil
|
250
|
+
model.counter.should == nil
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should work with float columns" do
|
254
|
+
model.float = "1.1"
|
255
|
+
model.float.should == 1.1
|
256
|
+
model.float = 2.2
|
257
|
+
model.float.should == 2.2
|
258
|
+
model.float = nil
|
259
|
+
model.float.should == nil
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should work with double columns" do
|
263
|
+
model.double = "1.1"
|
264
|
+
model.double.should == 1.1
|
265
|
+
model.double = 2.2
|
266
|
+
model.double.should == 2.2
|
267
|
+
model.double = nil
|
268
|
+
model.double.should == nil
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should work with decimal columns" do
|
272
|
+
model.decimal = "1.1"
|
273
|
+
model.decimal.should == 1.1
|
274
|
+
model.decimal.should be_a(BigDecimal)
|
275
|
+
model.decimal = BigDecimal.new("3.3", 2)
|
276
|
+
model.decimal.should == BigDecimal.new("3.3", 2)
|
277
|
+
model.decimal = nil
|
278
|
+
model.decimal.should == nil
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should work with timestamp columns" do
|
282
|
+
model.timestamp = "2015-04-23T15:23:30"
|
283
|
+
model.timestamp.should == Time.new(2015, 4, 23, 15, 23, 30)
|
284
|
+
model.timestamp = Time.new(2015, 4, 23, 15, 25, 30)
|
285
|
+
model.timestamp.should == Time.new(2015, 4, 23, 15, 25, 30)
|
286
|
+
model.timestamp = nil
|
287
|
+
model.timestamp.should == nil
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should work with boolean columns" do
|
291
|
+
model.boolean = true
|
292
|
+
model.boolean.should == true
|
293
|
+
model.boolean = false
|
294
|
+
model.boolean.should == false
|
295
|
+
model.boolean = nil
|
296
|
+
model.boolean.should == nil
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should work with inet columns" do
|
300
|
+
model.inet = "127.0.0.1"
|
301
|
+
model.inet.should == IPAddr.new("127.0.0.1")
|
302
|
+
model.inet = IPAddr.new("10.1.0.1")
|
303
|
+
model.inet.should == IPAddr.new("10.1.0.1")
|
304
|
+
model.inet = nil
|
305
|
+
model.inet.should == nil
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should work with uuid columns" do
|
309
|
+
model.uuid = "eed6d678-ea0b-11e4-8772-793f91a64daf"
|
310
|
+
model.uuid.should == Cassandra::Uuid.new("eed6d678-ea0b-11e4-8772-793f91a64daf")
|
311
|
+
model.uuid = Cassandra::Uuid.new("fed6d678-ea0b-11e4-8772-793f91a64daf")
|
312
|
+
model.uuid.should == Cassandra::Uuid.new("fed6d678-ea0b-11e4-8772-793f91a64daf")
|
313
|
+
model.uuid = nil
|
314
|
+
model.uuid.should == nil
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should work with timeuuid columns" do
|
318
|
+
model.timeuuid = "eed6d678-ea0b-11e4-8772-793f91a64daf"
|
319
|
+
model.timeuuid.should == Cassandra::TimeUuid.new("eed6d678-ea0b-11e4-8772-793f91a64daf")
|
320
|
+
model.timeuuid = Cassandra::TimeUuid.new("fed6d678-ea0b-11e4-8772-793f91a64daf")
|
321
|
+
model.timeuuid.should == Cassandra::TimeUuid.new("fed6d678-ea0b-11e4-8772-793f91a64daf")
|
322
|
+
model.timeuuid = nil
|
323
|
+
model.timeuuid.should == nil
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should work with list columns" do
|
327
|
+
model.list = ["a", "b", "c"]
|
328
|
+
model.list.should == ["a", "b", "c"]
|
329
|
+
model.list = nil
|
330
|
+
model.list.should == nil
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should work with set columns" do
|
334
|
+
model.set = ["a", "b", "c", "a"]
|
335
|
+
model.set.should == ["a", "b", "c"].to_set
|
336
|
+
model.set = nil
|
337
|
+
model.set.should == nil
|
338
|
+
end
|
339
|
+
|
340
|
+
it "should work with map columns" do
|
341
|
+
model.map = [["a", "b"], ["c", "d"]]
|
342
|
+
model.map.should == {"a" => "b", "c" => "d"}
|
343
|
+
model.map = {"e" => "f", "g" => "h"}
|
344
|
+
model.map.should == {"e" => "f", "g" => "h"}
|
345
|
+
model.map = nil
|
346
|
+
model.map.should == nil
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
data/spec/cassie_spec.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cassie do
|
4
|
+
|
5
|
+
let(:instance){ Cassie.instance }
|
6
|
+
let(:table){ "cassie_specs.things" }
|
7
|
+
|
8
|
+
describe "prepare" do
|
9
|
+
it "should keep a cache of prepared statements" do
|
10
|
+
statement_1 = instance.prepare("SELECT * FROM #{table} LIMIT ?")
|
11
|
+
statement_2 = instance.prepare("SELECT * FROM #{table} LIMIT ?")
|
12
|
+
statement_1.object_id.should == statement_2.object_id
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should clear the prepared statement cache when reconnecting" do
|
16
|
+
statement_1 = instance.prepare("SELECT * FROM #{table} LIMIT ?")
|
17
|
+
instance.disconnect
|
18
|
+
instance.connect
|
19
|
+
statement_2 = instance.prepare("SELECT * FROM #{table} LIMIT ?")
|
20
|
+
statement_1.object_id.should_not == statement_2.object_id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "find" do
|
25
|
+
before :each do
|
26
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
27
|
+
instance.insert(table, :owner => 10, :id => 2, :val => 'bar')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should construct a CQL query from the options" do
|
31
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = 1")
|
32
|
+
results.rows.collect{|r| r["val"]}.should == ['foo']
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should construct a CQL query from a statement with variables" do
|
36
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ? LIMIT ?", [10, 1])
|
37
|
+
results.rows.collect{|r| r["val"]}.should == ['bar']
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not batch find statements" do
|
41
|
+
instance.batch do
|
42
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ? LIMIT ?", [10, 1])
|
43
|
+
results.rows.collect{|r| r["val"]}.should == ['bar']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "insert" do
|
49
|
+
it "should insert a row from a hash of values" do
|
50
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
51
|
+
results.size.should == 0
|
52
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
53
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
54
|
+
results.rows.collect{|r| r['val']}.should == ['foo']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should add statements to the current batch" do
|
58
|
+
instance.batch do
|
59
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
60
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
61
|
+
results.size.should == 0
|
62
|
+
end
|
63
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
64
|
+
results.size.should == 1
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "update" do
|
69
|
+
it "should update a row from a hash of values and a primary key" do
|
70
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
71
|
+
instance.update(table, {:val => 'bar'}, :owner => 1, :id => 2)
|
72
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
73
|
+
results.rows.collect{|r| r["val"]}.should == ['bar']
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should add statements to the current batch" do
|
77
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
78
|
+
instance.batch do
|
79
|
+
instance.update(table, {:val => 'bar'}, :owner => 1, :id => 2)
|
80
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
81
|
+
results.rows.collect{|r| r['val']}.should == ['foo']
|
82
|
+
end
|
83
|
+
results = instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1)
|
84
|
+
results.rows.collect{|r| r['val']}.should == ['bar']
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "delete" do
|
89
|
+
it "should update a row from a primary key hash" do
|
90
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
91
|
+
instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1).size.should == 1
|
92
|
+
instance.delete(table, :owner => 1)
|
93
|
+
instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1).size.should == 0
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should add statements to the current batch" do
|
97
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
98
|
+
instance.batch do
|
99
|
+
instance.delete(table, :owner => 1)
|
100
|
+
instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1).size.should == 1
|
101
|
+
end
|
102
|
+
instance.find("SELECT owner, id, val FROM #{table} WHERE owner = ?", 1).size.should == 0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "execute" do
|
107
|
+
before :each do
|
108
|
+
instance.insert(table, :owner => 1, :id => 2, :val => 'foo')
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should execute a plain CQL statement" do
|
112
|
+
instance.execute("SELECT owner, id, val FROM #{table} WHERE owner = 1").size.should == 1
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should execute a prepared statement" do
|
116
|
+
statement = instance.prepare("SELECT owner, id, val FROM #{table} WHERE owner = 1")
|
117
|
+
instance.execute(statement).size.should == 1
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should prepare and execute a CQL statement when values are provided" do
|
121
|
+
instance.execute("SELECT owner, id, val FROM #{table} WHERE owner = ?", [1]).size.should == 1
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "consistency" do
|
126
|
+
let(:session){ instance.send(:session) }
|
127
|
+
|
128
|
+
it "should not specify query consistency by default" do
|
129
|
+
expect(session).to receive(:execute).with("SELECT * FROM dual", {})
|
130
|
+
instance.execute("SELECT * FROM dual")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow specifying the consistency in a block" do
|
134
|
+
expect(session).to receive(:execute).with("SELECT * FROM dual", {:consistency => :one})
|
135
|
+
Cassie.consistency(:one) do
|
136
|
+
instance.execute("SELECT * FROM dual")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should use the consistency specified to execute if provided" do
|
141
|
+
expect(session).to receive(:execute).with("SELECT * FROM dual", {:consistency => :two})
|
142
|
+
Cassie.consistency(:one) do
|
143
|
+
instance.execute("SELECT * FROM dual", nil, :consistency => :two)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Cassie::Thing
|
2
|
+
include Cassie::Model
|
3
|
+
|
4
|
+
self.table_name = "things"
|
5
|
+
self.keyspace = "test"
|
6
|
+
self.primary_key = [:owner, :id]
|
7
|
+
|
8
|
+
column :owner, :int
|
9
|
+
column :id, :int, :as => :identifier
|
10
|
+
column :val, :varchar, :as => :value
|
11
|
+
|
12
|
+
ordering_key :id, :desc
|
13
|
+
|
14
|
+
validates_presence_of :owner, :id
|
15
|
+
|
16
|
+
before_save do
|
17
|
+
callbacks << :save
|
18
|
+
end
|
19
|
+
|
20
|
+
before_create do
|
21
|
+
callbacks << :create
|
22
|
+
end
|
23
|
+
|
24
|
+
before_update do
|
25
|
+
callbacks << :update
|
26
|
+
end
|
27
|
+
|
28
|
+
before_destroy do
|
29
|
+
callbacks << :destroy
|
30
|
+
end
|
31
|
+
|
32
|
+
def callbacks
|
33
|
+
@callbacks ||= []
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Cassie::TypeTester
|
2
|
+
include Cassie::Model
|
3
|
+
|
4
|
+
column :int, :int
|
5
|
+
column :varint, :varint
|
6
|
+
column :bigint, :bigint
|
7
|
+
column :float, :float
|
8
|
+
column :double, :double
|
9
|
+
column :decimal, :decimal
|
10
|
+
column :ascii, :ascii
|
11
|
+
column :varchar, :varchar
|
12
|
+
column :text, :text
|
13
|
+
column :blob, :blob
|
14
|
+
column :boolean, :boolean
|
15
|
+
column :timestamp, :timestamp
|
16
|
+
column :counter, :counter
|
17
|
+
column :uuid, :uuid
|
18
|
+
column :timeuuid, :timeuuid
|
19
|
+
column :inet, :inet
|
20
|
+
column :list, :list
|
21
|
+
column :set, :set
|
22
|
+
column :map, :map
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'whi-cassie'
|
2
|
+
require File.expand_path('../models/thing', __FILE__)
|
3
|
+
require File.expand_path('../models/type_tester', __FILE__)
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.run_all_when_everything_filtered = true
|
7
|
+
config.filter_run :focus
|
8
|
+
|
9
|
+
# Run specs in random order to surface order dependencies. If you find an
|
10
|
+
# order dependency and want to debug it, you can fix the order by providing
|
11
|
+
# the seed, which is printed after each run.
|
12
|
+
# --seed 1234
|
13
|
+
config.order = 'random'
|
14
|
+
|
15
|
+
config.expect_with(:rspec) { |c| c.syntax = [:should, :expect] }
|
16
|
+
|
17
|
+
config.before(:suite) do
|
18
|
+
schema_dir = File.expand_path("../schema", __FILE__)
|
19
|
+
Cassie.configure!(:cluster => {:host => 'localhost'}, :keyspaces => {"test" => "cassie_specs"}, :schema_directory => schema_dir, :max_prepared_statements => 3)
|
20
|
+
Cassie::Schema.load_all!
|
21
|
+
Cassie::Testing.prepare!
|
22
|
+
end
|
23
|
+
|
24
|
+
config.after(:suite) do
|
25
|
+
Cassie::Schema.drop_all!
|
26
|
+
end
|
27
|
+
|
28
|
+
config.around(:each) do |example|
|
29
|
+
Cassie::Testing.cleanup! do
|
30
|
+
example.run
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/whi-cassie.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "whi-cassie"
|
7
|
+
spec.version = File.read(File.expand_path("../VERSION", __FILE__)).chomp
|
8
|
+
spec.authors = ["We Heart It", "Brian Durand"]
|
9
|
+
spec.email = ["dev@weheartit.com"]
|
10
|
+
spec.description = %q{Simple object mapper for Cassandra data tables.}
|
11
|
+
spec.summary = %q{Simple object mapper for Cassandra data tables specifically designed to work with the limitations and strengths of Cassandra.}
|
12
|
+
spec.homepage = "https://github.com/weheartit/cassie"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency('cassandra-driver', '~>2.1.3')
|
21
|
+
spec.add_dependency('activemodel', '~>4.0')
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~>1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", "~>2.0"
|
26
|
+
end
|