cequel 1.0.0.pre.4 → 1.0.0.pre.5
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 +4 -4
- data/lib/cequel/errors.rb +1 -0
- data/lib/cequel/record.rb +1 -0
- data/lib/cequel/record/bound.rb +101 -0
- data/lib/cequel/record/collection.rb +34 -8
- data/lib/cequel/record/persistence.rb +23 -3
- data/lib/cequel/record/properties.rb +8 -10
- data/lib/cequel/record/record_set.rb +55 -37
- data/lib/cequel/schema/column.rb +4 -0
- data/lib/cequel/schema/table_reader.rb +3 -3
- data/lib/cequel/type.rb +23 -17
- data/lib/cequel/version.rb +1 -1
- data/spec/examples/record/list_spec.rb +51 -0
- data/spec/examples/record/map_spec.rb +57 -0
- data/spec/examples/record/persistence_spec.rb +64 -0
- data/spec/examples/record/properties_spec.rb +19 -5
- data/spec/examples/record/record_set_spec.rb +126 -9
- data/spec/examples/record/schema_spec.rb +4 -0
- data/spec/examples/record/set_spec.rb +29 -0
- data/spec/examples/schema/table_reader_spec.rb +2 -2
- data/spec/support/helpers.rb +18 -0
- metadata +3 -2
@@ -61,11 +61,15 @@ describe Cequel::Record::Properties do
|
|
61
61
|
should == %w(one two three)
|
62
62
|
end
|
63
63
|
|
64
|
-
it 'should cast
|
65
|
-
Post.new { |post| post.tags = Set[1, 2, 3] }.tags.
|
64
|
+
it 'should cast collection in list column to list' do
|
65
|
+
Post.new { |post| post.tags = Set['1', '2', '3'] }.tags.
|
66
66
|
should == %w(1 2 3)
|
67
67
|
end
|
68
68
|
|
69
|
+
it 'should cast elements in list' do
|
70
|
+
Post.new { |post| post.tags = [1, 2, 3] }.tags.should == %w(1 2 3)
|
71
|
+
end
|
72
|
+
|
69
73
|
it 'should have empty list column value if unset' do
|
70
74
|
Post.new.tags.should == []
|
71
75
|
end
|
@@ -75,8 +79,13 @@ describe Cequel::Record::Properties do
|
|
75
79
|
categories.should == Set['Big Data', 'Cassandra']
|
76
80
|
end
|
77
81
|
|
78
|
-
it 'should cast values to correct type' do
|
79
|
-
Post.new { |post| post.categories = [1, 2, 3] }.categories.
|
82
|
+
it 'should cast values in set column to correct type' do
|
83
|
+
Post.new { |post| post.categories = Set[1, 2, 3] }.categories.
|
84
|
+
should == Set['1', '2', '3']
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should cast collection to set in set column' do
|
88
|
+
Post.new { |post| post.categories = ['1', '2', '3'] }.categories.
|
80
89
|
should == Set['1', '2', '3']
|
81
90
|
end
|
82
91
|
|
@@ -90,7 +99,12 @@ describe Cequel::Record::Properties do
|
|
90
99
|
end
|
91
100
|
|
92
101
|
it 'should cast values for map column' do
|
93
|
-
Post.new { |post| post.shares =
|
102
|
+
Post.new { |post| post.shares = {facebook: '1', twitter: '2'} }.
|
103
|
+
shares.should == {'facebook' => 1, 'twitter' => 2}
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should cast collection passed to map column to map' do
|
107
|
+
Post.new { |post| post.shares = [['facebook', 1], ['twitter', 2]] }.
|
94
108
|
shares.should == {'facebook' => 1, 'twitter' => 2}
|
95
109
|
end
|
96
110
|
|
@@ -2,18 +2,18 @@ require File.expand_path('../spec_helper', __FILE__)
|
|
2
2
|
|
3
3
|
describe Cequel::Record::RecordSet do
|
4
4
|
model :Blog do
|
5
|
-
key :subdomain, :
|
5
|
+
key :subdomain, :ascii
|
6
6
|
column :name, :text
|
7
7
|
column :description, :text
|
8
8
|
end
|
9
9
|
|
10
10
|
model :Post do
|
11
|
-
key :blog_subdomain, :
|
12
|
-
key :permalink, :
|
11
|
+
key :blog_subdomain, :ascii
|
12
|
+
key :permalink, :ascii
|
13
13
|
column :title, :text
|
14
14
|
column :body, :text
|
15
|
-
column :author_id, :uuid, :
|
16
|
-
column :author_name, :text, :
|
15
|
+
column :author_id, :uuid, index: true
|
16
|
+
column :author_name, :text, index: true
|
17
17
|
list :tags, :text
|
18
18
|
set :categories, :text
|
19
19
|
map :shares, :text, :int
|
@@ -23,8 +23,22 @@ describe Cequel::Record::RecordSet do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
model :Comment do
|
27
|
+
key :blog_subdomain, :text
|
28
|
+
key :permalink, :text
|
29
|
+
key :id, :uuid, :auto => true
|
30
|
+
column :body, :text
|
31
|
+
end
|
32
|
+
|
33
|
+
model :PublishedPost do
|
34
|
+
key :blog_subdomain, :ascii
|
35
|
+
key :published_at, :timeuuid
|
36
|
+
column :permalink, :ascii, index: true
|
37
|
+
end
|
38
|
+
|
26
39
|
let(:subdomains) { [] }
|
27
40
|
let(:uuids) { Array.new(2) { CassandraCQL::UUID.new }}
|
41
|
+
let(:now) { Time.at(Time.now.to_i) }
|
28
42
|
|
29
43
|
before do
|
30
44
|
cequel.batch do
|
@@ -35,8 +49,7 @@ describe Cequel::Record::RecordSet do
|
|
35
49
|
blog.description = "This is Blog number #{i}"
|
36
50
|
end.save
|
37
51
|
end
|
38
|
-
|
39
|
-
cequel.batch do
|
52
|
+
|
40
53
|
5.times do |i|
|
41
54
|
cequel[:posts].insert(
|
42
55
|
:blog_subdomain => 'cassandra',
|
@@ -45,12 +58,26 @@ describe Cequel::Record::RecordSet do
|
|
45
58
|
:body => "Post number #{i}",
|
46
59
|
:author_id => uuids[i%2]
|
47
60
|
)
|
61
|
+
cequel[:published_posts].insert(
|
62
|
+
:blog_subdomain => 'cassandra',
|
63
|
+
:published_at => max_uuid(now + (i - 4).minutes),
|
64
|
+
:permalink => "cequel#{i}"
|
65
|
+
)
|
48
66
|
cequel[:posts].insert(
|
49
67
|
:blog_subdomain => 'postgres',
|
50
68
|
:permalink => "sequel#{i}",
|
51
69
|
:title => "Sequel #{i}"
|
52
70
|
)
|
53
71
|
end
|
72
|
+
|
73
|
+
5.times do |i|
|
74
|
+
cequel[:comments].insert(
|
75
|
+
:blog_subdomain => 'cassandra',
|
76
|
+
:permalink => 'cequel0',
|
77
|
+
:id => CassandraCQL::UUID.new(Time.now - 5 + i),
|
78
|
+
:body => "Comment #{i}"
|
79
|
+
)
|
80
|
+
end
|
54
81
|
end
|
55
82
|
end
|
56
83
|
|
@@ -66,7 +93,11 @@ describe Cequel::Record::RecordSet do
|
|
66
93
|
specify { Blog.new.should_not be_persisted }
|
67
94
|
specify { Blog.new.should be_transient }
|
68
95
|
|
69
|
-
|
96
|
+
it 'should cast argument to correct type' do
|
97
|
+
Blog.find('blog-0'.force_encoding('ASCII-8BIT')).should be
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should raise RecordNotFound if bad argument passed' do
|
70
101
|
expect { Blog.find('bogus') }.
|
71
102
|
to raise_error(Cequel::Record::RecordNotFound)
|
72
103
|
end
|
@@ -84,7 +115,12 @@ describe Cequel::Record::RecordSet do
|
|
84
115
|
specify { Post.new.should_not be_persisted }
|
85
116
|
specify { Post.new.should be_transient }
|
86
117
|
|
87
|
-
|
118
|
+
it 'should cast all keys to correct type' do
|
119
|
+
Post['cassandra'.force_encoding('ASCII-8BIT')].
|
120
|
+
find('cequel0'.force_encoding('ASCII-8BIT')).should be
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should raise RecordNotFound if bad argument passed' do
|
88
124
|
expect { Post['cequel'].find('bogus')}.
|
89
125
|
to raise_error(Cequel::Record::RecordNotFound)
|
90
126
|
end
|
@@ -109,6 +145,10 @@ describe Cequel::Record::RecordSet do
|
|
109
145
|
disallow_queries!
|
110
146
|
subject.description.should == 'This is Blog number 0'
|
111
147
|
end
|
148
|
+
|
149
|
+
it 'should cast argument' do
|
150
|
+
subject.subdomain.encoding.name.should == 'US-ASCII'
|
151
|
+
end
|
112
152
|
end
|
113
153
|
|
114
154
|
context 'compound primary key' do
|
@@ -120,6 +160,11 @@ describe Cequel::Record::RecordSet do
|
|
120
160
|
subject.permalink.should == 'cequel0'
|
121
161
|
end
|
122
162
|
|
163
|
+
it 'should cast all keys to the correct type' do
|
164
|
+
subject.blog_subdomain.encoding.name.should == 'US-ASCII'
|
165
|
+
subject.permalink.encoding.name.should == 'US-ASCII'
|
166
|
+
end
|
167
|
+
|
123
168
|
it 'should lazily query the database when attribute accessed' do
|
124
169
|
subject.title.should == 'Cequel 0'
|
125
170
|
end
|
@@ -155,6 +200,12 @@ describe Cequel::Record::RecordSet do
|
|
155
200
|
Post.at('cassandra').find_each(:batch_size => 2).map(&:title).
|
156
201
|
should == (0...5).map { |i| "Cequel #{i}" }
|
157
202
|
end
|
203
|
+
|
204
|
+
it 'should cast arguments correctly' do
|
205
|
+
Post.at('cassandra'.force_encoding('ASCII-8BIT')).
|
206
|
+
find_each(:batch_size => 2).map(&:title).
|
207
|
+
should == (0...5).map { |i| "Cequel #{i}" }
|
208
|
+
end
|
158
209
|
end
|
159
210
|
|
160
211
|
describe '#[]' do
|
@@ -176,6 +227,16 @@ describe Cequel::Record::RecordSet do
|
|
176
227
|
Post.at('cassandra').after('cequel1').map(&:title).
|
177
228
|
should == (2...5).map { |i| "Cequel #{i}" }
|
178
229
|
end
|
230
|
+
|
231
|
+
it 'should cast argument' do
|
232
|
+
Post.at('cassandra').after('cequel1'.force_encoding('ASCII-8BIT')).
|
233
|
+
map(&:title).should == (2...5).map { |i| "Cequel #{i}" }
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should query Time range for Timeuuid key' do
|
237
|
+
PublishedPost['cassandra'].after(now - 3.minutes).map(&:permalink).
|
238
|
+
should == %w(cequel2 cequel3 cequel4)
|
239
|
+
end
|
179
240
|
end
|
180
241
|
|
181
242
|
describe '#from' do
|
@@ -184,6 +245,16 @@ describe Cequel::Record::RecordSet do
|
|
184
245
|
should == (1...5).map { |i| "Cequel #{i}" }
|
185
246
|
end
|
186
247
|
|
248
|
+
it 'should cast argument' do
|
249
|
+
Post.at('cassandra').from('cequel1'.force_encoding('ASCII-8BIT')).
|
250
|
+
map(&:title).should == (1...5).map { |i| "Cequel #{i}" }
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should query Time range for Timeuuid key' do
|
254
|
+
PublishedPost['cassandra'].from(now - 3.minutes).map(&:permalink).
|
255
|
+
should == %w(cequel1 cequel2 cequel3 cequel4)
|
256
|
+
end
|
257
|
+
|
187
258
|
it 'should raise ArgumentError when called on partition key' do
|
188
259
|
expect { Post.from('cassandra') }.
|
189
260
|
to raise_error(Cequel::Record::IllegalQuery)
|
@@ -195,6 +266,16 @@ describe Cequel::Record::RecordSet do
|
|
195
266
|
Post.at('cassandra').before('cequel3').map(&:title).
|
196
267
|
should == (0...3).map { |i| "Cequel #{i}" }
|
197
268
|
end
|
269
|
+
|
270
|
+
it 'should query Time range for Timeuuid key' do
|
271
|
+
PublishedPost['cassandra'].before(now - 1.minute).map(&:permalink).
|
272
|
+
should == %w(cequel0 cequel1 cequel2)
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'should cast argument' do
|
276
|
+
Post.at('cassandra').before('cequel3'.force_encoding('ASCII-8BIT')).
|
277
|
+
map(&:title).should == (0...3).map { |i| "Cequel #{i}" }
|
278
|
+
end
|
198
279
|
end
|
199
280
|
|
200
281
|
describe '#upto' do
|
@@ -202,6 +283,16 @@ describe Cequel::Record::RecordSet do
|
|
202
283
|
Post.at('cassandra').upto('cequel3').map(&:title).
|
203
284
|
should == (0..3).map { |i| "Cequel #{i}" }
|
204
285
|
end
|
286
|
+
|
287
|
+
it 'should cast argument' do
|
288
|
+
Post.at('cassandra').upto('cequel3'.force_encoding('ASCII-8BIT')).
|
289
|
+
map(&:title).should == (0..3).map { |i| "Cequel #{i}" }
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should query Time range for Timeuuid key' do
|
293
|
+
PublishedPost['cassandra'].upto(now - 1.minute).map(&:permalink).
|
294
|
+
should == %w(cequel0 cequel1 cequel2 cequel3)
|
295
|
+
end
|
205
296
|
end
|
206
297
|
|
207
298
|
describe '#in' do
|
@@ -210,10 +301,26 @@ describe Cequel::Record::RecordSet do
|
|
210
301
|
should == (1..3).map { |i| "Cequel #{i}" }
|
211
302
|
end
|
212
303
|
|
304
|
+
it 'should cast arguments' do
|
305
|
+
Post.at('cassandra').in('cequel1'.force_encoding('ASCII-8BIT')..
|
306
|
+
'cequel3'.force_encoding('ASCII-8BIT')).
|
307
|
+
map(&:title).should == (1..3).map { |i| "Cequel #{i}" }
|
308
|
+
end
|
309
|
+
|
213
310
|
it 'should return collection with exclusive upper bound' do
|
214
311
|
Post.at('cassandra').in('cequel1'...'cequel3').map(&:title).
|
215
312
|
should == (1...3).map { |i| "Cequel #{i}" }
|
216
313
|
end
|
314
|
+
|
315
|
+
it 'should query Time range for Timeuuid key' do
|
316
|
+
PublishedPost['cassandra'].in((now - 3.minutes)..(now - 1.minute)).
|
317
|
+
map(&:permalink).should == %w(cequel1 cequel2 cequel3)
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'should query Time range for Timeuuid key with exclusive upper bound' do
|
321
|
+
PublishedPost['cassandra'].in((now - 3.minutes)...(now - 1.minute)).
|
322
|
+
map(&:permalink).should == %w(cequel1 cequel2)
|
323
|
+
end
|
217
324
|
end
|
218
325
|
|
219
326
|
describe '#reverse' do
|
@@ -235,6 +342,11 @@ describe Cequel::Record::RecordSet do
|
|
235
342
|
it 'should raise an error if range key is a partition key' do
|
236
343
|
expect { Post.all.reverse }.to raise_error(Cequel::Record::IllegalQuery)
|
237
344
|
end
|
345
|
+
|
346
|
+
it 'should use the correct ordering column in deeply nested models' do
|
347
|
+
Comment['cassandra']['cequel0'].reverse.map(&:body).
|
348
|
+
should == (0...5).map { |i| "Comment #{i}" }.reverse
|
349
|
+
end
|
238
350
|
end
|
239
351
|
|
240
352
|
describe 'last' do
|
@@ -295,6 +407,11 @@ describe Cequel::Record::RecordSet do
|
|
295
407
|
should == %w(cequel0 cequel2 cequel4)
|
296
408
|
end
|
297
409
|
|
410
|
+
it 'should cast argument for column' do
|
411
|
+
Post.where(:author_id, uuids.first.to_s).map(&:permalink).
|
412
|
+
should == %w(cequel0 cequel2 cequel4)
|
413
|
+
end
|
414
|
+
|
298
415
|
it 'should raise ArgumentError if column is not recognized' do
|
299
416
|
expect { Post.where(:bogus, 'Business') }.
|
300
417
|
to raise_error(ArgumentError)
|
@@ -83,6 +83,10 @@ describe Cequel::Record::Schema do
|
|
83
83
|
its(:clustering_columns) { should == [Cequel::Schema::Column.new(:id, :uuid)] }
|
84
84
|
it { should be_compact_storage }
|
85
85
|
its(:data_columns) { should == [Cequel::Schema::Column.new(:data, :text)] }
|
86
|
+
|
87
|
+
it 'should be able to synchronize schema again' do
|
88
|
+
expect { legacy_model.synchronize_schema }.to_not raise_error
|
89
|
+
end
|
86
90
|
end
|
87
91
|
end
|
88
92
|
end
|
@@ -27,6 +27,20 @@ describe Cequel::Record::Set do
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
context 'updating' do
|
31
|
+
it 'should overwrite value' do
|
32
|
+
post.tags = Set['three', 'four']
|
33
|
+
post.save!
|
34
|
+
subject[:tags].should == Set['three', 'four']
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should cast collection before overwriting' do
|
38
|
+
post.tags = %w(three four)
|
39
|
+
post.save!
|
40
|
+
subject[:tags].should == Set['three', 'four']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
30
44
|
describe 'atomic modification' do
|
31
45
|
before { scope.set_add(:tags, 'three') }
|
32
46
|
|
@@ -38,6 +52,11 @@ describe Cequel::Record::Set do
|
|
38
52
|
post.tags.should == Set['one', 'two', 'four']
|
39
53
|
end
|
40
54
|
|
55
|
+
it 'should cast before adding' do
|
56
|
+
post.tags.add(4)
|
57
|
+
post.tags.should == Set['one', 'two', '4']
|
58
|
+
end
|
59
|
+
|
41
60
|
it 'should add without reading' do
|
42
61
|
max_statements! 2
|
43
62
|
unloaded_post.tags.add('four')
|
@@ -80,6 +99,11 @@ describe Cequel::Record::Set do
|
|
80
99
|
post.tags.should == Set['one']
|
81
100
|
end
|
82
101
|
|
102
|
+
it 'should cast before deleting' do
|
103
|
+
post.tags.delete(:two)
|
104
|
+
post.tags.should == Set['one']
|
105
|
+
end
|
106
|
+
|
83
107
|
it 'should delete without reading' do
|
84
108
|
max_statements! 2
|
85
109
|
unloaded_post.tags.delete('two')
|
@@ -101,6 +125,11 @@ describe Cequel::Record::Set do
|
|
101
125
|
post.tags.should == Set['a', 'b']
|
102
126
|
end
|
103
127
|
|
128
|
+
it 'should cast before replacing' do
|
129
|
+
post.tags.replace(Set[1, 2, :three])
|
130
|
+
post.tags.should == Set['1', '2', 'three']
|
131
|
+
end
|
132
|
+
|
104
133
|
it 'should replace without reading' do
|
105
134
|
max_statements! 2
|
106
135
|
unloaded_post.tags.replace(Set['a', 'b'])
|
@@ -381,9 +381,9 @@ describe Cequel::Schema::TableReader do
|
|
381
381
|
its(:partition_key_columns) { should ==
|
382
382
|
[Cequel::Schema::PartitionKey.new(:blog_subdomain, :text)] }
|
383
383
|
its(:clustering_columns) { should ==
|
384
|
-
[Cequel::Schema::ClusteringColumn.new(
|
384
|
+
[Cequel::Schema::ClusteringColumn.new(:column1, :uuid)] }
|
385
385
|
its(:data_columns) { should ==
|
386
|
-
[Cequel::Schema::DataColumn.new(
|
386
|
+
[Cequel::Schema::DataColumn.new(:value, :text)] }
|
387
387
|
end
|
388
388
|
|
389
389
|
end
|
data/spec/support/helpers.rb
CHANGED
@@ -76,6 +76,24 @@ module Cequel
|
|
76
76
|
)
|
77
77
|
end
|
78
78
|
|
79
|
+
def min_uuid(time = Time.now)
|
80
|
+
CassandraCQL::UUID.new(time, :randomize => false)
|
81
|
+
end
|
82
|
+
|
83
|
+
def max_uuid(time = Time.now)
|
84
|
+
time = time.stamp * 10 + SimpleUUID::UUID::GREGORIAN_EPOCH_OFFSET
|
85
|
+
# See http://github.com/spectra/ruby-uuid/
|
86
|
+
byte_array = [
|
87
|
+
time & 0xFFFF_FFFF,
|
88
|
+
time >> 32,
|
89
|
+
((time >> 48) & 0x0FFF) | 0x1000,
|
90
|
+
(2**13 - 1) | SimpleUUID::UUID::VARIANT,
|
91
|
+
2**16 - 1,
|
92
|
+
2**32 - 1
|
93
|
+
]
|
94
|
+
CassandraCQL::UUID.new(byte_array.pack("NnnnnN"))
|
95
|
+
end
|
96
|
+
|
79
97
|
def cequel
|
80
98
|
Helpers.cequel
|
81
99
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.
|
4
|
+
version: 1.0.0.pre.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mat Brown
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2013-
|
15
|
+
date: 2013-11-08 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activesupport
|
@@ -154,6 +154,7 @@ files:
|
|
154
154
|
- lib/cequel/record/association_collection.rb
|
155
155
|
- lib/cequel/record/associations.rb
|
156
156
|
- lib/cequel/record/belongs_to_association.rb
|
157
|
+
- lib/cequel/record/bound.rb
|
157
158
|
- lib/cequel/record/callbacks.rb
|
158
159
|
- lib/cequel/record/collection.rb
|
159
160
|
- lib/cequel/record/dirty.rb
|