cequel 0.5.6 → 1.0.0.pre.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.
- checksums.yaml +7 -0
- data/lib/cequel.rb +5 -8
- data/lib/cequel/errors.rb +1 -0
- data/lib/cequel/metal.rb +17 -0
- data/lib/cequel/metal/batch.rb +62 -0
- data/lib/cequel/metal/cql_row_specification.rb +26 -0
- data/lib/cequel/metal/data_set.rb +461 -0
- data/lib/cequel/metal/deleter.rb +47 -0
- data/lib/cequel/metal/incrementer.rb +35 -0
- data/lib/cequel/metal/inserter.rb +53 -0
- data/lib/cequel/metal/keyspace.rb +213 -0
- data/lib/cequel/metal/row.rb +48 -0
- data/lib/cequel/metal/row_specification.rb +37 -0
- data/lib/cequel/metal/statement.rb +30 -0
- data/lib/cequel/metal/updater.rb +65 -0
- data/lib/cequel/metal/writer.rb +73 -0
- data/lib/cequel/model.rb +12 -84
- data/lib/cequel/model/association_collection.rb +23 -0
- data/lib/cequel/model/associations.rb +84 -80
- data/lib/cequel/model/base.rb +74 -0
- data/lib/cequel/model/belongs_to_association.rb +31 -0
- data/lib/cequel/model/callbacks.rb +14 -10
- data/lib/cequel/model/collection.rb +255 -0
- data/lib/cequel/model/errors.rb +6 -6
- data/lib/cequel/model/has_many_association.rb +26 -0
- data/lib/cequel/model/mass_assignment.rb +31 -0
- data/lib/cequel/model/persistence.rb +119 -115
- data/lib/cequel/model/properties.rb +89 -87
- data/lib/cequel/model/railtie.rb +21 -14
- data/lib/cequel/model/record_set.rb +285 -0
- data/lib/cequel/model/schema.rb +33 -0
- data/lib/cequel/model/scoped.rb +5 -48
- data/lib/cequel/model/validations.rb +18 -18
- data/lib/cequel/schema.rb +15 -0
- data/lib/cequel/schema/column.rb +135 -0
- data/lib/cequel/schema/create_table_dsl.rb +56 -0
- data/lib/cequel/schema/keyspace.rb +50 -0
- data/lib/cequel/schema/table.rb +120 -0
- data/lib/cequel/schema/table_property.rb +67 -0
- data/lib/cequel/schema/table_reader.rb +139 -0
- data/lib/cequel/schema/table_synchronizer.rb +114 -0
- data/lib/cequel/schema/table_updater.rb +83 -0
- data/lib/cequel/schema/table_writer.rb +80 -0
- data/lib/cequel/schema/update_table_dsl.rb +60 -0
- data/lib/cequel/type.rb +232 -0
- data/lib/cequel/version.rb +1 -1
- data/spec/environment.rb +5 -1
- data/spec/examples/metal/data_set_spec.rb +608 -0
- data/spec/examples/model/associations_spec.rb +84 -74
- data/spec/examples/model/callbacks_spec.rb +66 -59
- data/spec/examples/model/list_spec.rb +393 -0
- data/spec/examples/model/map_spec.rb +229 -0
- data/spec/examples/model/mass_assignment_spec.rb +55 -0
- data/spec/examples/model/naming_spec.rb +11 -4
- data/spec/examples/model/persistence_spec.rb +140 -150
- data/spec/examples/model/properties_spec.rb +122 -75
- data/spec/examples/model/record_set_spec.rb +285 -0
- data/spec/examples/model/schema_spec.rb +44 -0
- data/spec/examples/model/serialization_spec.rb +20 -14
- data/spec/examples/model/set_spec.rb +133 -0
- data/spec/examples/model/spec_helper.rb +0 -10
- data/spec/examples/model/validations_spec.rb +51 -38
- data/spec/examples/schema/table_reader_spec.rb +328 -0
- data/spec/examples/schema/table_synchronizer_spec.rb +172 -0
- data/spec/examples/schema/table_updater_spec.rb +157 -0
- data/spec/examples/schema/table_writer_spec.rb +225 -0
- data/spec/examples/spec_helper.rb +29 -0
- data/spec/examples/type_spec.rb +204 -0
- data/spec/support/helpers.rb +67 -8
- metadata +121 -152
- data/lib/cequel/batch.rb +0 -58
- data/lib/cequel/cql_row_specification.rb +0 -22
- data/lib/cequel/data_set.rb +0 -371
- data/lib/cequel/keyspace.rb +0 -205
- data/lib/cequel/model/class_internals.rb +0 -49
- data/lib/cequel/model/column.rb +0 -20
- data/lib/cequel/model/counter.rb +0 -35
- data/lib/cequel/model/dictionary.rb +0 -126
- data/lib/cequel/model/dirty.rb +0 -53
- data/lib/cequel/model/dynamic.rb +0 -31
- data/lib/cequel/model/inheritable.rb +0 -48
- data/lib/cequel/model/instance_internals.rb +0 -23
- data/lib/cequel/model/local_association.rb +0 -42
- data/lib/cequel/model/magic.rb +0 -79
- data/lib/cequel/model/mass_assignment_security.rb +0 -21
- data/lib/cequel/model/naming.rb +0 -17
- data/lib/cequel/model/observer.rb +0 -42
- data/lib/cequel/model/readable_dictionary.rb +0 -182
- data/lib/cequel/model/remote_association.rb +0 -40
- data/lib/cequel/model/scope.rb +0 -362
- data/lib/cequel/model/subclass_internals.rb +0 -45
- data/lib/cequel/model/timestamps.rb +0 -52
- data/lib/cequel/model/translation.rb +0 -17
- data/lib/cequel/row_specification.rb +0 -63
- data/lib/cequel/statement.rb +0 -23
- data/spec/examples/data_set_spec.rb +0 -444
- data/spec/examples/keyspace_spec.rb +0 -84
- data/spec/examples/model/counter_spec.rb +0 -94
- data/spec/examples/model/dictionary_spec.rb +0 -301
- data/spec/examples/model/dirty_spec.rb +0 -39
- data/spec/examples/model/dynamic_spec.rb +0 -41
- data/spec/examples/model/inheritable_spec.rb +0 -45
- data/spec/examples/model/magic_spec.rb +0 -199
- data/spec/examples/model/mass_assignment_security_spec.rb +0 -13
- data/spec/examples/model/observer_spec.rb +0 -86
- data/spec/examples/model/scope_spec.rb +0 -677
- data/spec/examples/model/timestamps_spec.rb +0 -52
- data/spec/examples/model/translation_spec.rb +0 -23
@@ -1,39 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Dirty do
|
4
|
-
let(:post) { Post.new(:id => 1) }
|
5
|
-
|
6
|
-
it 'should not have changed attributes by default' do
|
7
|
-
post.changed_attributes.should be_empty
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should have changed attributes if attributes change' do
|
11
|
-
post.title = 'Cequel'
|
12
|
-
post.changed_attributes.should == {:title => nil}.with_indifferent_access
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should not have changed attributes if attribute set to the same thing' do
|
16
|
-
post.title = nil
|
17
|
-
post.changed_attributes.should be_empty
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should support *_changed? method' do
|
21
|
-
post.title = 'Cequel'
|
22
|
-
post.title_changed?.should be_true
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should not have changed attributes after save' do
|
26
|
-
connection.stub(:execute)
|
27
|
-
post.title = 'Cequel'
|
28
|
-
post.save
|
29
|
-
post.changed_attributes.should be_empty
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should have previous changes after save' do
|
33
|
-
connection.stub(:execute)
|
34
|
-
post.title = 'Cequel'
|
35
|
-
post.save
|
36
|
-
post.previous_changes.
|
37
|
-
should == { :title => [nil, 'Cequel'] }.with_indifferent_access
|
38
|
-
end
|
39
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Dynamic do
|
4
|
-
|
5
|
-
let(:category) { Category.new(:id => 1, :name => 'Big Data') }
|
6
|
-
|
7
|
-
it 'should allow getting and setting of dynamic attributes' do
|
8
|
-
category[:tag] = 'bigdata'
|
9
|
-
category[:tag].should == 'bigdata'
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should insert dynamic values' do
|
13
|
-
category[:tag] = 'bigdata'
|
14
|
-
connection.should_receive(:execute).
|
15
|
-
with "INSERT INTO categories (?) VALUES (?)", ['id', 'name', 'tag'], [1, 'Big Data', 'bigdata']
|
16
|
-
category.save
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should update dynamic values' do
|
20
|
-
category[:tag] = 'bigdata'
|
21
|
-
connection.stub(:execute).
|
22
|
-
with "INSERT INTO categories (?) VALUES (?)", ['id', 'name', 'tag'], [1, 'Big Data', 'bigdata']
|
23
|
-
category.save
|
24
|
-
category[:tag] = 'big-data'
|
25
|
-
category[:color] = 'blue'
|
26
|
-
connection.should_receive(:execute).
|
27
|
-
with "UPDATE categories SET ? = ?, ? = ? WHERE ? = ?", 'tag', 'big-data', 'color', 'blue', :id, 1
|
28
|
-
category.save
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should delete dynamic values' do
|
32
|
-
category[:tag] = 'bigdata'
|
33
|
-
connection.stub(:execute).
|
34
|
-
with "INSERT INTO categories (?) VALUES (?)", ['id', 'name', 'tag'], [1, 'Big Data', 'bigdata']
|
35
|
-
category.save
|
36
|
-
category[:tag] = nil
|
37
|
-
connection.should_receive(:execute).
|
38
|
-
with "DELETE ? FROM categories WHERE ? = ?", ['tag'], :id, 1
|
39
|
-
category.save
|
40
|
-
end
|
41
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Inheritable do
|
4
|
-
it 'should inherit key from superclass' do
|
5
|
-
Photo.key_alias.should == :id
|
6
|
-
end
|
7
|
-
|
8
|
-
it 'should inherit columns from superclass' do
|
9
|
-
Photo.column_names.should == [:id, :class_name, :label, :checksum, :url]
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should return ::base_class for base class' do
|
13
|
-
Asset.base_class.should == Asset
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should return ::base_class for subclass' do
|
17
|
-
Photo.base_class.should == Asset
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should not allow overriding a class without a type column' do
|
21
|
-
base = Class.new do
|
22
|
-
include Cequel::Model
|
23
|
-
key :id, :integer
|
24
|
-
end
|
25
|
-
expect { sub = Class.new(base) }.to raise_error(ArgumentError)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should set type on initialization' do
|
29
|
-
Photo.new.class_name.should == 'Photo'
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should query correct column family when querying subclass' do
|
33
|
-
connection.stub(:execute).
|
34
|
-
with("SELECT * FROM assets WHERE ? = ? LIMIT 1", :id, 1).
|
35
|
-
and_return result_stub(:id => 1, :label => 'Cequel')
|
36
|
-
Photo.find(1)
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should hydrate correct model class when querying base class' do
|
40
|
-
connection.stub(:execute).
|
41
|
-
with('SELECT * FROM assets WHERE ? = ? LIMIT 1', :id, 1).
|
42
|
-
and_return result_stub(:id => 1, :class_name => 'Photo', :label => 'Cequel')
|
43
|
-
Asset.find(1).should be_a(Photo)
|
44
|
-
end
|
45
|
-
end
|
@@ -1,199 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Magic do
|
4
|
-
describe '::find_by_*' do
|
5
|
-
it 'should magically look up one record by given value' do
|
6
|
-
connection.stub(:execute).
|
7
|
-
with("SELECT * FROM posts WHERE ? = ? LIMIT 1", :title, 'Cequel').
|
8
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
9
|
-
|
10
|
-
Post.find_by_title('Cequel').id.should == 1
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should magically look up one record by multiple values' do
|
14
|
-
connection.stub(:execute).
|
15
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
16
|
-
and_return result_stub(:id => 1, :title => 'Cequel', :published => true)
|
17
|
-
|
18
|
-
Post.find_by_title_and_published('Cequel', true).id.should == 1
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should magically work on scopes' do
|
22
|
-
connection.stub(:execute).
|
23
|
-
with("SELECT ? FROM posts WHERE ? = ? AND ? = ? LIMIT 1", [:id], :title, 'Cequel', :published, true).
|
24
|
-
and_return result_stub(:id => 1)
|
25
|
-
|
26
|
-
Post.select(:id).find_by_title_and_published('Cequel', true).id.should == 1
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should raise error if specified columns different from arg count' do
|
30
|
-
expect { Post.find_by_title_and_published('Cequel') }.
|
31
|
-
to raise_error(ArgumentError)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe '::find_all_by_*' do
|
36
|
-
context 'with existing record specified as args' do
|
37
|
-
it 'should magically look up one record by multiple values' do
|
38
|
-
connection.stub(:execute).
|
39
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ?", :title, 'Cequel', :published, true).
|
40
|
-
and_return result_stub(
|
41
|
-
{:id => 1, :title => 'Cequel', :published => true},
|
42
|
-
{:id => 2, :title => 'Cequel2', :published => true }
|
43
|
-
)
|
44
|
-
|
45
|
-
Post.find_all_by_title_and_published('Cequel', true).map(&:id).
|
46
|
-
should == [1, 2]
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'should magically work on scopes' do
|
50
|
-
connection.stub(:execute).
|
51
|
-
with("SELECT ? FROM posts WHERE ? = ? AND ? = ?", [:id], :title, 'Cequel', :published, true).
|
52
|
-
and_return result_stub(
|
53
|
-
{:id => 1},
|
54
|
-
{:id => 2}
|
55
|
-
)
|
56
|
-
|
57
|
-
Post.select(:id).find_all_by_title_and_published('Cequel', true).map(&:id).
|
58
|
-
should == [1, 2]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe '::find_or_create_by_*' do
|
64
|
-
it 'should return existing record from args' do
|
65
|
-
connection.stub(:execute).
|
66
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
67
|
-
and_return result_stub(:id => 1, :title => 'Cequel', :published => true)
|
68
|
-
|
69
|
-
Post.find_or_create_by_title_and_published('Cequel', true).id.should == 1
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'should create new record from args' do
|
73
|
-
now = Time.now
|
74
|
-
Time.stub!(:now).and_return now
|
75
|
-
connection.stub(:execute).
|
76
|
-
with("SELECT * FROM blogs WHERE ? = ? LIMIT 1", :id, 1).
|
77
|
-
and_return result_stub
|
78
|
-
connection.should_receive(:execute).
|
79
|
-
with(
|
80
|
-
"INSERT INTO blogs (?) VALUES (?)",
|
81
|
-
['id', 'published', 'updated_at', 'created_at'],
|
82
|
-
[1, true, now, now]
|
83
|
-
)
|
84
|
-
|
85
|
-
Blog.find_or_create_by_id(1).id.should == 1
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'should look up record from attributes' do
|
89
|
-
connection.stub(:execute).
|
90
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
91
|
-
and_return result_stub(:id => 1, :title => 'Cequel', :published => true)
|
92
|
-
|
93
|
-
Post.find_or_create_by_title_and_published(
|
94
|
-
:id => 2, :title => 'Cequel', :published => true
|
95
|
-
).id.should == 1
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'should create record from all attributes specified, including non-lookup ones' do
|
99
|
-
connection.stub(:execute).
|
100
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
101
|
-
and_return result_stub
|
102
|
-
connection.should_receive(:execute).
|
103
|
-
with(
|
104
|
-
"INSERT INTO posts (?) VALUES (?)",
|
105
|
-
['id', 'title', 'published'],
|
106
|
-
[2, 'Cequel', true])
|
107
|
-
|
108
|
-
Post.find_or_create_by_title_and_published(
|
109
|
-
:id => 2, :title => 'Cequel', :published => true
|
110
|
-
).id.should == 2
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'should yield instance on create if block given' do
|
114
|
-
connection.stub(:execute).
|
115
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
116
|
-
and_return result_stub
|
117
|
-
connection.should_receive(:execute).
|
118
|
-
with(
|
119
|
-
"INSERT INTO posts (?) VALUES (?)",
|
120
|
-
['id', 'title', 'published'],
|
121
|
-
[2, 'Cequel', true]
|
122
|
-
)
|
123
|
-
|
124
|
-
Post.find_or_create_by_title_and_published('Cequel', true) do |post|
|
125
|
-
post.id = 2
|
126
|
-
end.id.should == 2
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'should work on scopes' do
|
130
|
-
connection.stub(:execute).
|
131
|
-
with("SELECT ? FROM posts WHERE ? = ? AND ? = ? LIMIT 1", [:id], :title, 'Cequel', :published, true).
|
132
|
-
and_return result_stub(:id => 1)
|
133
|
-
|
134
|
-
Post.select(:id).find_or_create_by_title_and_published('Cequel', true).id.
|
135
|
-
should == 1
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
describe '::find_or_initialize_by_*' do
|
140
|
-
it 'should return existing record from args' do
|
141
|
-
connection.stub(:execute).
|
142
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
143
|
-
and_return result_stub(:id => 1, :title => 'Cequel', :published => true)
|
144
|
-
|
145
|
-
Post.find_or_initialize_by_title_and_published('Cequel', true).id.should == 1
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'should initialize new record from args' do
|
149
|
-
now = Time.now
|
150
|
-
Time.stub!(:now).and_return now
|
151
|
-
timestamp = (now.to_f * 1000).to_i
|
152
|
-
connection.stub(:execute).
|
153
|
-
with("SELECT * FROM blogs WHERE ? = ? LIMIT 1", :id, 1).
|
154
|
-
and_return result_stub
|
155
|
-
|
156
|
-
Blog.find_or_initialize_by_id(1).id.should == 1
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'should look up record from attributes' do
|
160
|
-
connection.stub(:execute).
|
161
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
162
|
-
and_return result_stub(:id => 1, :title => 'Cequel', :published => true)
|
163
|
-
|
164
|
-
Post.find_or_initialize_by_title_and_published(
|
165
|
-
:id => 2, :title => 'Cequel', :published => true
|
166
|
-
).id.should == 1
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'should create record from all attributes specified, including non-lookup ones' do
|
170
|
-
connection.stub(:execute).
|
171
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
172
|
-
and_return result_stub
|
173
|
-
|
174
|
-
Post.find_or_initialize_by_title_and_published(
|
175
|
-
:id => 2, :title => 'Cequel', :published => true
|
176
|
-
).id.should == 2
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'should yield instance on initialize if block given' do
|
180
|
-
connection.stub(:execute).
|
181
|
-
with("SELECT * FROM posts WHERE ? = ? AND ? = ? LIMIT 1", :title, 'Cequel', :published, true).
|
182
|
-
and_return result_stub
|
183
|
-
|
184
|
-
Post.find_or_initialize_by_title_and_published('Cequel', true) do |post|
|
185
|
-
post.id = 2
|
186
|
-
end.id.should == 2
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'should work on scopes' do
|
190
|
-
connection.stub(:execute).
|
191
|
-
with("SELECT ? FROM posts WHERE ? = ? AND ? = ? LIMIT 1", [:id], :title, 'Cequel', :published, true).
|
192
|
-
and_return result_stub(:id => 1)
|
193
|
-
|
194
|
-
Post.select(:id).find_or_initialize_by_title_and_published('Cequel', true).id.
|
195
|
-
should == 1
|
196
|
-
end
|
197
|
-
|
198
|
-
end
|
199
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::MassAssignmentSecurity do
|
4
|
-
let(:post) { Post.new(:id => 1, :title => 'Cequel', :blog_id => 3) }
|
5
|
-
|
6
|
-
it 'should allow setting of unprotected attributes' do
|
7
|
-
post.title.should == 'Cequel'
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should not allow setting of protected attributes' do
|
11
|
-
post.blog_id.should be_nil
|
12
|
-
end
|
13
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Observer do
|
4
|
-
before do
|
5
|
-
Cequel::Model.observers = [:post_observer, :asset_observer]
|
6
|
-
Cequel::Model.instantiate_observers
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:post) do
|
10
|
-
connection.stub(:execute).
|
11
|
-
with("SELECT * FROM posts WHERE ? = ? LIMIT 1", :id, 1).
|
12
|
-
and_return result_stub('id' => 1, 'title' => 'Hey')
|
13
|
-
Post.find(1)
|
14
|
-
end
|
15
|
-
|
16
|
-
shared_examples_for 'observing callbacks' do |*callbacks|
|
17
|
-
|
18
|
-
all_callbacks = [
|
19
|
-
:before_create, :after_create, :before_update, :after_update,
|
20
|
-
:before_save, :after_save, :before_destroy, :after_destroy,
|
21
|
-
:before_validation, :after_validation
|
22
|
-
]
|
23
|
-
|
24
|
-
callbacks.each do |callback|
|
25
|
-
it "should observe #{callback}" do
|
26
|
-
post.should have_been_observed(callback)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
(all_callbacks - callbacks).each do |callback|
|
31
|
-
it "should not observe #{callback}" do
|
32
|
-
post.should_not have_been_observed(callback)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'on create' do
|
38
|
-
let(:post) do
|
39
|
-
connection.stub(:execute).
|
40
|
-
with "INSERT INTO posts (?) VALUES (?)", ['id', 'title'], [1, 'Hey']
|
41
|
-
Post.new(:id => 1, :title => 'Hey')
|
42
|
-
end
|
43
|
-
|
44
|
-
before { post.save }
|
45
|
-
|
46
|
-
it_should_behave_like 'observing callbacks',
|
47
|
-
:before_create, :after_create, :before_save, :after_save, :before_validation, :after_validation
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'on update' do
|
51
|
-
|
52
|
-
before { post.save }
|
53
|
-
|
54
|
-
it_should_behave_like 'observing callbacks',
|
55
|
-
:before_update, :after_update, :before_save, :after_save, :before_validation, :after_validation
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'on destroy 'do
|
59
|
-
|
60
|
-
before do
|
61
|
-
connection.stub(:execute).
|
62
|
-
with "DELETE FROM posts WHERE ? = ?", :id, 1
|
63
|
-
|
64
|
-
post.destroy
|
65
|
-
end
|
66
|
-
|
67
|
-
it_should_behave_like 'observing callbacks', :before_destroy, :after_destroy
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'on validation' do
|
71
|
-
before do
|
72
|
-
post.valid?
|
73
|
-
end
|
74
|
-
|
75
|
-
it_should_behave_like 'observing callbacks', :before_validation, :after_validation
|
76
|
-
end
|
77
|
-
|
78
|
-
context 'with inheritence' do
|
79
|
-
it 'should observe subclass' do
|
80
|
-
connection.stub(:execute).
|
81
|
-
with("INSERT INTO assets (?) VALUES (?)", ['id', 'label', 'class_name'], [1, 'Cequel', 'Photo'])
|
82
|
-
photo = Photo.create!(:id => 1, :label => 'Cequel')
|
83
|
-
photo.should have_observed(:before_save)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,677 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
|
3
|
-
describe Cequel::Model::Scope do
|
4
|
-
describe '#each' do
|
5
|
-
it 'should provide enumerator for query results' do
|
6
|
-
connection.stub(:execute).with("SELECT * FROM posts").
|
7
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
8
|
-
|
9
|
-
Post.all.map { |post| [post.id, post.title] }.
|
10
|
-
should == [[1, 'Cequel']]
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should enumerate results for just id if no key restriction' do
|
14
|
-
connection.stub(:execute).with("SELECT ? FROM posts", [:id]).
|
15
|
-
and_return result_stub(:id => 1)
|
16
|
-
|
17
|
-
Post.select(:id).to_a.map { |post| post.id }.should == [1]
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should not enumerate results for just id if key restriction' do
|
21
|
-
connection.stub(:execute).with("SELECT * FROM posts").
|
22
|
-
and_return result_stub(:id => 1)
|
23
|
-
|
24
|
-
Post.all.to_a.map { |post| post.id }.should == []
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should provide enumerator if no block given' do
|
28
|
-
enum = Post.all.each
|
29
|
-
|
30
|
-
connection.stub(:execute).with("SELECT * FROM posts").
|
31
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
32
|
-
|
33
|
-
enum.map { |post| post.title }.should == ['Cequel']
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should enumerate zero times if empty-collection key restriction given' do
|
37
|
-
Post.where(:id => []).to_a.should == []
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should enumerate zero times if empty-collection restriction given' do
|
41
|
-
Post.where(:title => []).to_a.should == []
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe '#first' do
|
46
|
-
it 'should query for a single post' do
|
47
|
-
connection.stub(:execute).with("SELECT * FROM posts LIMIT 1").
|
48
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
49
|
-
|
50
|
-
Post.first.title.should == 'Cequel'
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'should query for a single post within scope' do
|
54
|
-
connection.stub(:execute).with("SELECT ? FROM posts LIMIT 1", [:id, :title]).
|
55
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
56
|
-
|
57
|
-
Post.select(:id, :title).first.title.should == 'Cequel'
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'should query scopes successively when multi-valued non-key column selected' do
|
61
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ? LIMIT 1", :title, 'Cequel').
|
62
|
-
and_return result_stub
|
63
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ? LIMIT 1", :title, 'Cassandra').
|
64
|
-
and_return result_stub(:id => 1, :title => 'Cassandra')
|
65
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ? LIMIT 1", :title, 'CQL').
|
66
|
-
and_return result_stub(:id => 2, :title => 'CQL')
|
67
|
-
|
68
|
-
Post.where(:title => %w(Cequel Cassandra CQL)).first.title.
|
69
|
-
should == 'Cassandra'
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'should apply index preference when specified' do
|
73
|
-
connection.should_receive(:execute).
|
74
|
-
with("SELECT * FROM assets WHERE ? = ? AND ? = ? LIMIT 1", :checksum, 'abcdef', :class_name, 'Photo').
|
75
|
-
and_return result_stub
|
76
|
-
Photo.where(:checksum => 'abcdef').first
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should return nil when empty key collection given' do
|
80
|
-
Post.where(:id => []).first.should be_nil
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'should return nil when empty non-key collection given' do
|
84
|
-
Post.where(:title => []).first.should be_nil
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe '#count' do
|
89
|
-
it 'should count records' do
|
90
|
-
connection.stub(:execute).with("SELECT COUNT(*) FROM posts").
|
91
|
-
and_return result_stub('count' => 5)
|
92
|
-
|
93
|
-
Post.count.should == 5
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'should count records in scope' do
|
97
|
-
connection.stub(:execute).
|
98
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
99
|
-
and_return result_stub('count' => 5)
|
100
|
-
|
101
|
-
Post.where(:blog_id => 1).count.should == 5
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'should raise error if attempting count with key restriction' do
|
105
|
-
expect { Post.where(:id => [1, 2, 3]).count }.
|
106
|
-
to raise_error(Cequel::Model::InvalidQuery)
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'should perform multiple COUNT queries if non-key column selected for multiple values' do
|
110
|
-
connection.stub(:execute).
|
111
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
112
|
-
and_return result_stub('count' => 3)
|
113
|
-
connection.stub(:execute).
|
114
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 2).
|
115
|
-
and_return result_stub('count' => 2)
|
116
|
-
|
117
|
-
Post.where(:blog_id => [1, 2]).count.should == 5
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'should return nil if empty non-key restriction given' do
|
121
|
-
Post.where(:title => []).count.should == 0
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'should apply index preference when specified' do
|
125
|
-
connection.should_receive(:execute).
|
126
|
-
with("SELECT COUNT(*) FROM assets WHERE ? = ? AND ? = ?", :checksum, 'abcdef', :class_name, 'Photo').
|
127
|
-
and_return result_stub('count' => 0)
|
128
|
-
Photo.where(:checksum => 'abcdef').count
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
describe '#find' do
|
133
|
-
it 'should send scoped query when no block is passed' do
|
134
|
-
connection.stub(:execute).
|
135
|
-
with("SELECT ? FROM posts WHERE ? = ? LIMIT 1", [:id, :title], :id, 1).
|
136
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
137
|
-
|
138
|
-
Post.select(:id, :title).find(1).title.should == 'Cequel'
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'should send scoped query with multiple keys when no block is passed' do
|
142
|
-
connection.stub(:execute).
|
143
|
-
with("SELECT ? FROM posts WHERE ? IN (?)", [:id, :title], :id, [1, 2]).
|
144
|
-
and_return result_stub(
|
145
|
-
{:id => 1, :title => 'Cequel'},
|
146
|
-
{:id => 2, :title => 'Cequel 2'}
|
147
|
-
)
|
148
|
-
|
149
|
-
Post.select(:id, :title).find(1, 2).
|
150
|
-
map { |post| post.title }.should == ['Cequel', 'Cequel 2']
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'should delegate to enumerator when block is passed' do
|
154
|
-
connection.stub(:execute).
|
155
|
-
with("SELECT ? FROM posts", [:id, :title]).
|
156
|
-
and_return result_stub(
|
157
|
-
{:id => 1, :title => 'Cequel'},
|
158
|
-
{:id => 2, :title => 'Cequel 2'}
|
159
|
-
)
|
160
|
-
|
161
|
-
Post.select(:id, :title).find { |post| post.id == 2 }.title.
|
162
|
-
should == 'Cequel 2'
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
describe '#any?' do
|
167
|
-
it 'if called without block, should return true if COUNT > 0' do
|
168
|
-
connection.stub(:execute).
|
169
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
170
|
-
and_return result_stub('count' => 5)
|
171
|
-
|
172
|
-
Post.where(:blog_id => 1).any?.should be_true
|
173
|
-
end
|
174
|
-
|
175
|
-
it 'if called without block, should return false if COUNT == 0' do
|
176
|
-
connection.stub(:execute).
|
177
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
178
|
-
and_return result_stub('count' => 0)
|
179
|
-
|
180
|
-
Post.where(:blog_id => 1).any?.should be_false
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'if called with block should delegate to enumerator' do
|
184
|
-
connection.stub(:execute).
|
185
|
-
with("SELECT * FROM posts WHERE ? = ?", :blog_id, 1).
|
186
|
-
and_return result_stub(
|
187
|
-
{:id => 1, :title => 'Cequel'},
|
188
|
-
{:id => 2, :title => 'Cequel 2'}
|
189
|
-
)
|
190
|
-
|
191
|
-
Post.where(:blog_id => 1).any? { |post| post.id == 1 }.should be_true
|
192
|
-
Post.where(:blog_id => 1).any? { |post| post.id == 8 }.should be_false
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe '#none?' do
|
197
|
-
it 'if called without block, should return false if COUNT > 0' do
|
198
|
-
connection.stub(:execute).
|
199
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
200
|
-
and_return result_stub('count' => 5)
|
201
|
-
|
202
|
-
Post.where(:blog_id => 1).none?.should be_false
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'if called without block, should return true if COUNT == 0' do
|
206
|
-
connection.stub(:execute).
|
207
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
208
|
-
and_return result_stub('count' => 0)
|
209
|
-
|
210
|
-
Post.where(:blog_id => 1).none?.should be_true
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'if called with block should delegate to enumerator' do
|
214
|
-
connection.stub(:execute).
|
215
|
-
with("SELECT * FROM posts WHERE ? = ?", :blog_id, 1).
|
216
|
-
and_return result_stub(
|
217
|
-
{:id => 1, :title => 'Cequel'},
|
218
|
-
{:id => 2, :title => 'Cequel 2'}
|
219
|
-
)
|
220
|
-
|
221
|
-
Post.where(:blog_id => 1).none? { |post| post.id == 1 }.should be_false
|
222
|
-
Post.where(:blog_id => 1).none? { |post| post.id == 8 }.should be_true
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
describe '#one?' do
|
227
|
-
it 'if called without block, should return false if COUNT == 0' do
|
228
|
-
connection.stub(:execute).
|
229
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
230
|
-
and_return result_stub('count' => 0)
|
231
|
-
|
232
|
-
Post.where(:blog_id => 1).one?.should be_false
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'if called without block, should return true if COUNT == 1' do
|
236
|
-
connection.stub(:execute).
|
237
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
238
|
-
and_return result_stub('count' => 1)
|
239
|
-
|
240
|
-
Post.where(:blog_id => 1).one?.should be_true
|
241
|
-
end
|
242
|
-
|
243
|
-
it 'if called without block, should return false if COUNT > 1' do
|
244
|
-
connection.stub(:execute).
|
245
|
-
with("SELECT COUNT(*) FROM posts WHERE ? = ?", :blog_id, 1).
|
246
|
-
and_return result_stub('count' => 12)
|
247
|
-
|
248
|
-
Post.where(:blog_id => 1).one?.should be_false
|
249
|
-
end
|
250
|
-
|
251
|
-
it 'if called with block should delegate to enumerator' do
|
252
|
-
connection.stub(:execute).
|
253
|
-
with("SELECT * FROM posts WHERE ? = ?", :blog_id, 1).
|
254
|
-
and_return result_stub(
|
255
|
-
{:id => 1, :title => 'Cequel'},
|
256
|
-
{:id => 2, :title => 'Cequel 2'}
|
257
|
-
)
|
258
|
-
|
259
|
-
Post.where(:blog_id => 1).none? { |post| post.id == 1 }.should be_false
|
260
|
-
Post.where(:blog_id => 1).none? { |post| post.id == 8 }.should be_true
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
describe '#find_in_batches' do
|
265
|
-
it 'should select in batches of given size' do
|
266
|
-
connection.stub(:execute).with("SELECT * FROM posts LIMIT 2").
|
267
|
-
and_return result_stub(
|
268
|
-
{:id => 1, :title => 'Post 1'},
|
269
|
-
{:id => 2, :title => 'Post 2'}
|
270
|
-
)
|
271
|
-
connection.stub(:execute).
|
272
|
-
with("SELECT * FROM posts WHERE ? > ? LIMIT 2", :id, 2).
|
273
|
-
and_return result_stub(:id => 3, :title => 'Post 3')
|
274
|
-
batches = []
|
275
|
-
Post.find_in_batches(:batch_size => 2) do |batch|
|
276
|
-
batches << batch
|
277
|
-
end
|
278
|
-
batches.map { |batch| batch.map(&:title) }.should ==
|
279
|
-
[['Post 1', 'Post 2'], ['Post 3']]
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'should not duplicate last key if given back first in next batch' do
|
283
|
-
connection.stub(:execute).with("SELECT * FROM posts LIMIT 2").
|
284
|
-
and_return result_stub(
|
285
|
-
{:id => 1, :title => 'Post 1'},
|
286
|
-
{:id => 2, :title => 'Post 2'}
|
287
|
-
)
|
288
|
-
connection.stub(:execute).
|
289
|
-
with("SELECT * FROM posts WHERE ? > ? LIMIT 2", :id, 2).
|
290
|
-
and_return result_stub(
|
291
|
-
{:id => 2, :title => 'Post 2'},
|
292
|
-
{:id => 3, :title => 'Post 3'}
|
293
|
-
)
|
294
|
-
connection.stub(:execute).
|
295
|
-
with("SELECT * FROM posts WHERE ? > ? LIMIT 2", :id, 3).
|
296
|
-
and_return result_stub()
|
297
|
-
batches = []
|
298
|
-
Post.find_in_batches(:batch_size => 2) do |batch|
|
299
|
-
batches << batch
|
300
|
-
end
|
301
|
-
batches.map { |batch| batch.map(&:title) }.should ==
|
302
|
-
[['Post 1', 'Post 2'], ['Post 3']]
|
303
|
-
end
|
304
|
-
|
305
|
-
it 'should iterate over batches of keys' do
|
306
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? IN (?)", :id, [1, 2]).
|
307
|
-
and_return result_stub(
|
308
|
-
{:id => 1, :title => 'Post 1'},
|
309
|
-
{:id => 2, :title => 'Post 2'}
|
310
|
-
)
|
311
|
-
connection.stub(:execute).
|
312
|
-
with("SELECT * FROM posts WHERE ? = ?", :id, 3).
|
313
|
-
and_return result_stub(:id => 3, :title => 'Post 3')
|
314
|
-
batches = []
|
315
|
-
Post.where(:id => [1, 2, 3]).find_in_batches(:batch_size => 2) do |batch|
|
316
|
-
batches << batch
|
317
|
-
end
|
318
|
-
batches.map { |batch| batch.map(&:title) }.should ==
|
319
|
-
[['Post 1', 'Post 2'], ['Post 3']]
|
320
|
-
end
|
321
|
-
|
322
|
-
it 'should respect scope' do
|
323
|
-
connection.stub(:execute).with("SELECT ? FROM posts LIMIT 2", [:id, :title]).
|
324
|
-
and_return result_stub(
|
325
|
-
{:id => 1, :title => 'Post 1'},
|
326
|
-
{:id => 2, :title => 'Post 2'}
|
327
|
-
)
|
328
|
-
connection.stub(:execute).
|
329
|
-
with("SELECT ? FROM posts WHERE ? > ? LIMIT 2", [:id, :title], :id, 2).
|
330
|
-
and_return result_stub(:id => 3, :title => 'Post 3')
|
331
|
-
batches = []
|
332
|
-
Post.select(:id, :title).find_in_batches(:batch_size => 2) do |batch|
|
333
|
-
batches << batch
|
334
|
-
end
|
335
|
-
batches.map { |batch| batch.map(&:title) }.should ==
|
336
|
-
[['Post 1', 'Post 2'], ['Post 3']]
|
337
|
-
end
|
338
|
-
|
339
|
-
it 'should add key column to SELECT if omitted' do
|
340
|
-
connection.stub(:execute).with("SELECT ? FROM posts LIMIT 2", [:title, :id]).
|
341
|
-
and_return result_stub(
|
342
|
-
{:id => 1, :title => 'Post 1'},
|
343
|
-
{:id => 2, :title => 'Post 2'}
|
344
|
-
)
|
345
|
-
connection.stub(:execute).
|
346
|
-
with("SELECT ? FROM posts WHERE ? > ? LIMIT 2", [:title, :id], :id, 2).
|
347
|
-
and_return result_stub(:id => 3, :title => 'Post 3')
|
348
|
-
batches = []
|
349
|
-
Post.select(:title).find_in_batches(:batch_size => 2) do |batch|
|
350
|
-
batches << batch
|
351
|
-
end
|
352
|
-
batches.map { |batch| batch.map(&:title) }.should ==
|
353
|
-
[['Post 1', 'Post 2'], ['Post 3']]
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
describe '#find_each' do
|
358
|
-
it 'should iterate over batches and yield results one by one' do
|
359
|
-
connection.stub(:execute).with("SELECT * FROM posts LIMIT 2").
|
360
|
-
and_return result_stub(
|
361
|
-
{:id => 1, :title => 'Post 1'},
|
362
|
-
{:id => 2, :title => 'Post 2'}
|
363
|
-
)
|
364
|
-
connection.stub(:execute).
|
365
|
-
with("SELECT * FROM posts WHERE ? > ? LIMIT 2", :id, 2).
|
366
|
-
and_return result_stub(:id => 3, :title => 'Post 3')
|
367
|
-
Post.find_each(:batch_size => 2).map { |post| post.title }.
|
368
|
-
should == ['Post 1', 'Post 2', 'Post 3']
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
describe '#select' do
|
373
|
-
it 'should scope columns in data set' do
|
374
|
-
connection.stub(:execute).with("SELECT ? FROM posts", [:id, :title]).
|
375
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
376
|
-
|
377
|
-
Post.select(:id, :title).map { |post| post.title }.should == ['Cequel']
|
378
|
-
end
|
379
|
-
|
380
|
-
it 'should fail fast if attempting to select only key column with restrictions on key column' do
|
381
|
-
expect { Post.where(:id => 1).select(:id) }.
|
382
|
-
to raise_error(Cequel::Model::InvalidQuery)
|
383
|
-
end
|
384
|
-
|
385
|
-
it 'should delegate to enumerator if block given' do
|
386
|
-
connection.stub(:execute).
|
387
|
-
with("SELECT * FROM posts WHERE ? = ?", :blog_id, 1).
|
388
|
-
and_return result_stub(
|
389
|
-
{:id => 1, :title => 'Cequel'},
|
390
|
-
{:id => 2, :title => 'Cequel 2'},
|
391
|
-
{:id => 3, :title => 'Cequel 3'}
|
392
|
-
)
|
393
|
-
|
394
|
-
Post.where(:blog_id => 1).select { |post| post.id < 3 }.
|
395
|
-
map { |post| post.title }.should == ['Cequel', 'Cequel 2']
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
describe '#select!' do
|
400
|
-
it 'should override previous columns in data set' do
|
401
|
-
connection.stub(:execute).with("SELECT ? FROM posts", [:id, :published]).
|
402
|
-
and_return result_stub(:id => 1, :published => true)
|
403
|
-
|
404
|
-
Post.select(:id, :title).select!(:id, :published).
|
405
|
-
map { |post| post.published }.should == [true]
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
describe '#consistency' do
|
410
|
-
it 'should scope consistency in data set' do
|
411
|
-
connection.stub(:execute).with("SELECT * FROM posts USING CONSISTENCY QUORUM").
|
412
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
413
|
-
|
414
|
-
Post.consistency(:quorum).map { |post| post.title }.should == ['Cequel']
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
describe '#where' do
|
419
|
-
it 'should scope to row specifications in data set' do
|
420
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ?", :id, 1).
|
421
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
422
|
-
|
423
|
-
Post.where(:id => 1).map { |post| post.title }.should == ['Cequel']
|
424
|
-
end
|
425
|
-
|
426
|
-
it 'should perform multiple queries if IN query performed on non-key column' do
|
427
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ?", :title, 'Cequel').
|
428
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
429
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ?", :title, 'Fun').
|
430
|
-
and_return result_stub(
|
431
|
-
{:id => 2, :title => 'Fun'},
|
432
|
-
{:id => 3, :title => 'Fun'}
|
433
|
-
)
|
434
|
-
Post.where(:title => %w(Cequel Fun)).map(&:id).
|
435
|
-
should == [1, 2, 3]
|
436
|
-
end
|
437
|
-
|
438
|
-
it 'should fail fast if attempting to select only key column with restrictions on key column' do
|
439
|
-
expect { Post.select(:id).where(:id => 1) }.
|
440
|
-
to raise_error(Cequel::Model::InvalidQuery)
|
441
|
-
end
|
442
|
-
|
443
|
-
it 'should fail fast if attempting to mix key and non-key columns' do
|
444
|
-
expect { Post.where(:id => 1).where(:title => 'Cequel') }.
|
445
|
-
to raise_error(Cequel::Model::InvalidQuery)
|
446
|
-
end
|
447
|
-
|
448
|
-
it 'should use index preference if given' do
|
449
|
-
connection.should_receive(:execute).
|
450
|
-
with("SELECT * FROM assets WHERE ? = ? AND ? = ?", :checksum, 'abcdef', :class_name, 'Photo').
|
451
|
-
and_return result_stub
|
452
|
-
Photo.where(:checksum => 'abcdef').to_a
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
describe '#where!' do
|
457
|
-
it 'should override previously chained row specifications' do
|
458
|
-
connection.stub(:execute).with("SELECT * FROM posts WHERE ? = ?", :title, 'Cequel').
|
459
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
460
|
-
|
461
|
-
Post.where(:id => 1).where!(:title => 'Cequel').
|
462
|
-
map { |post| post.title }.should == ['Cequel']
|
463
|
-
end
|
464
|
-
end
|
465
|
-
|
466
|
-
describe '#limit' do
|
467
|
-
it 'should limit results in data set' do
|
468
|
-
connection.stub(:execute).with("SELECT * FROM posts LIMIT 5").
|
469
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
470
|
-
|
471
|
-
Post.limit(5).map { |post| post.title }.should == ['Cequel']
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
describe 'chaining' do
|
476
|
-
it 'should aggregate scopes' do
|
477
|
-
connection.stub(:execute).
|
478
|
-
with("SELECT ? FROM posts USING CONSISTENCY QUORUM WHERE ? = ? LIMIT 5", [:id, :title], :blog_id, 1).
|
479
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
480
|
-
|
481
|
-
Post.select(:id, :title).
|
482
|
-
consistency(:quorum).
|
483
|
-
where(:blog_id => 1).
|
484
|
-
limit(5).
|
485
|
-
map { |post| post.title }.should == ['Cequel']
|
486
|
-
end
|
487
|
-
|
488
|
-
it 'should delegate unknown methods to the underlying class with self as current scope' do
|
489
|
-
connection.stub(:execute).
|
490
|
-
with("SELECT ? FROM posts USING CONSISTENCY QUORUM WHERE ? = ? LIMIT 5", [:id, :title], :blog_id, 1).
|
491
|
-
and_return result_stub(:id => 1, :title => 'Cequel')
|
492
|
-
|
493
|
-
Post.select(:id, :title).
|
494
|
-
consistency(:quorum).
|
495
|
-
for_blog(1).
|
496
|
-
limit(5).
|
497
|
-
map { |post| post.title }.should == ['Cequel']
|
498
|
-
end
|
499
|
-
|
500
|
-
end
|
501
|
-
|
502
|
-
describe '#update_all' do
|
503
|
-
context 'with no scope restrictions' do
|
504
|
-
let(:scope) { Post }
|
505
|
-
|
506
|
-
it 'should get all keys and then update htem' do
|
507
|
-
connection.should_receive(:execute).
|
508
|
-
with("SELECT ? FROM posts", [:id]).
|
509
|
-
and_return result_stub(
|
510
|
-
{:id => 1},
|
511
|
-
{:id => 2}
|
512
|
-
)
|
513
|
-
connection.should_receive(:execute).
|
514
|
-
with "UPDATE posts SET ? = ? WHERE ? IN (?)", :title, 'Cequel', :id, [1, 2]
|
515
|
-
scope.update_all(:title => 'Cequel')
|
516
|
-
end
|
517
|
-
end
|
518
|
-
|
519
|
-
context 'with scope selecting on ids' do
|
520
|
-
let(:scope) { Post.where(:id => [1, 2]) }
|
521
|
-
|
522
|
-
it 'should issue scoped update request' do
|
523
|
-
connection.should_receive(:execute).
|
524
|
-
with "UPDATE posts SET ? = ? WHERE ? IN (?)", :title, 'Cequel', :id, [1, 2]
|
525
|
-
scope.update_all(:title => 'Cequel')
|
526
|
-
end
|
527
|
-
|
528
|
-
end
|
529
|
-
|
530
|
-
context 'with scope selecting on non-IDs' do
|
531
|
-
let(:scope) { Post.where(:published => false) }
|
532
|
-
|
533
|
-
it 'should perform "subquery" and issue update' do
|
534
|
-
connection.stub(:execute).
|
535
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :published, false).
|
536
|
-
and_return result_stub({:id => 1}, {:id => 2})
|
537
|
-
|
538
|
-
connection.should_receive(:execute).
|
539
|
-
with "UPDATE posts SET ? = ? WHERE ? IN (?)", :title, 'Cequel', :id, [1, 2]
|
540
|
-
|
541
|
-
scope.update_all(:title => 'Cequel')
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
context 'with scope selecting multiple values on non-key column' do
|
546
|
-
let(:scope) { Post.where(:title => %w(Cequel Cassandra)) }
|
547
|
-
|
548
|
-
it 'should perform multiple subqueries and execute single update on returned keys' do
|
549
|
-
connection.stub(:execute).
|
550
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :title, 'Cequel').
|
551
|
-
and_return result_stub({:id => 1}, {:id => 2})
|
552
|
-
|
553
|
-
connection.stub(:execute).
|
554
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :title, 'Cassandra').
|
555
|
-
and_return result_stub({:id => 3}, {:id => 4})
|
556
|
-
|
557
|
-
connection.should_receive(:execute).
|
558
|
-
with "UPDATE posts SET ? = ? WHERE ? IN (?)", :published, true, :id, [1, 2, 3, 4]
|
559
|
-
|
560
|
-
scope.update_all(:published => true)
|
561
|
-
end
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
describe '#destroy_all' do
|
566
|
-
context 'with no scope restrictions' do
|
567
|
-
let(:scope) { Post }
|
568
|
-
|
569
|
-
it 'should destroy all instances' do
|
570
|
-
connection.should_receive(:execute).
|
571
|
-
with('SELECT * FROM posts').
|
572
|
-
and_return result_stub(
|
573
|
-
{'id' => 1, 'title' => 'Cequel'},
|
574
|
-
{'id' => 2, 'title' => 'Cassandra'}
|
575
|
-
)
|
576
|
-
connection.should_receive(:execute).
|
577
|
-
with "DELETE FROM posts WHERE ? = ?", :id, 1
|
578
|
-
connection.should_receive(:execute).
|
579
|
-
with "DELETE FROM posts WHERE ? = ?", :id, 2
|
580
|
-
scope.destroy_all
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
|
-
context 'with column restrictions' do
|
585
|
-
let(:scope) { Post.where(:id => [1, 2]) }
|
586
|
-
|
587
|
-
it 'should issue scoped update request' do
|
588
|
-
connection.should_receive(:execute).
|
589
|
-
with("SELECT * FROM posts WHERE ? IN (?)", :id, [1, 2]).
|
590
|
-
and_return result_stub(
|
591
|
-
{'id' => 1, 'title' => 'Cequel'},
|
592
|
-
{'id' => 2, 'title' => 'Cassandra'}
|
593
|
-
)
|
594
|
-
connection.should_receive(:execute).
|
595
|
-
with "DELETE FROM posts WHERE ? = ?", :id, 1
|
596
|
-
connection.should_receive(:execute).
|
597
|
-
with "DELETE FROM posts WHERE ? = ?", :id, 2
|
598
|
-
scope.destroy_all
|
599
|
-
end
|
600
|
-
|
601
|
-
end
|
602
|
-
end
|
603
|
-
|
604
|
-
describe '#delete_all' do
|
605
|
-
context 'with no scope restrictions' do
|
606
|
-
let(:scope) { Post }
|
607
|
-
|
608
|
-
it 'should truncate keyspace' do
|
609
|
-
connection.should_receive(:execute).
|
610
|
-
with "TRUNCATE posts"
|
611
|
-
Post.delete_all
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
context 'with scope selecting on ids' do
|
616
|
-
let(:scope) { Post.where(:id => [1, 2]) }
|
617
|
-
|
618
|
-
it 'should issue scoped delete request' do
|
619
|
-
connection.should_receive(:execute).
|
620
|
-
with "DELETE FROM posts WHERE ? IN (?)", :id, [1, 2]
|
621
|
-
scope.delete_all
|
622
|
-
end
|
623
|
-
|
624
|
-
end
|
625
|
-
|
626
|
-
context 'with scope selecting on non-IDs' do
|
627
|
-
let(:scope) { Post.where(:published => false) }
|
628
|
-
|
629
|
-
it 'should perform "subquery" and issue update' do
|
630
|
-
connection.stub(:execute).
|
631
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :published, false).
|
632
|
-
and_return result_stub({:id => 1}, {:id => 2})
|
633
|
-
|
634
|
-
connection.should_receive(:execute).
|
635
|
-
with "DELETE FROM posts WHERE ? IN (?)", :id, [1, 2]
|
636
|
-
|
637
|
-
scope.delete_all
|
638
|
-
end
|
639
|
-
end
|
640
|
-
|
641
|
-
context 'with scope selecting multiple values on non-key column' do
|
642
|
-
let(:scope) { Post.where(:title => %w(Cequel Cassandra)) }
|
643
|
-
|
644
|
-
it 'should perform multiple subqueries and execute single update on returned keys' do
|
645
|
-
connection.stub(:execute).
|
646
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :title, 'Cequel').
|
647
|
-
and_return result_stub({:id => 1}, {:id => 2})
|
648
|
-
|
649
|
-
connection.stub(:execute).
|
650
|
-
with("SELECT ? FROM posts WHERE ? = ?", [:id], :title, 'Cassandra').
|
651
|
-
and_return result_stub({:id => 3}, {:id => 4})
|
652
|
-
|
653
|
-
connection.should_receive(:execute).
|
654
|
-
with "DELETE FROM posts WHERE ? IN (?)", :id, [1, 2, 3, 4]
|
655
|
-
|
656
|
-
scope.delete_all
|
657
|
-
end
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
describe '::default_scope' do
|
662
|
-
it 'should include in scope by default' do
|
663
|
-
connection.should_receive(:execute).
|
664
|
-
with("SELECT * FROM blogs LIMIT 100").and_return result_stub
|
665
|
-
|
666
|
-
Blog.all.to_a
|
667
|
-
end
|
668
|
-
|
669
|
-
it 'should override as with normal scope' do
|
670
|
-
connection.should_receive(:execute).
|
671
|
-
with("SELECT * FROM blogs LIMIT 1000").and_return result_stub
|
672
|
-
|
673
|
-
Blog.limit(1000).to_a
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
end
|