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,109 +1,119 @@
|
|
1
|
-
|
1
|
+
require_relative 'spec_helper'
|
2
2
|
|
3
3
|
describe Cequel::Model::Associations do
|
4
4
|
|
5
|
+
model :Blog do
|
6
|
+
key :subdomain, :text
|
7
|
+
column :name, :text
|
8
|
+
|
9
|
+
has_many :posts
|
10
|
+
end
|
11
|
+
|
12
|
+
model :User do
|
13
|
+
key :login, :text
|
14
|
+
column :name, :text
|
15
|
+
end
|
16
|
+
|
17
|
+
model :Post do
|
18
|
+
belongs_to :blog
|
19
|
+
key :id, :uuid
|
20
|
+
column :title, :text
|
21
|
+
end
|
22
|
+
|
5
23
|
describe '::belongs_to' do
|
6
|
-
let(:
|
7
|
-
|
8
|
-
end
|
24
|
+
let(:blog) { Blog.new { |blog| blog.subdomain = 'big-data' }}
|
25
|
+
let(:post) { Post.new }
|
9
26
|
|
10
|
-
|
11
|
-
|
12
|
-
with('SELECT * FROM blogs WHERE ? = ? LIMIT 1', :id, 2).
|
13
|
-
and_return result_stub(:id => 2, :name => 'Big Data Blog')
|
27
|
+
it 'should add parent key as first key' do
|
28
|
+
Post.key_column_names.first.should == :blog_subdomain
|
14
29
|
end
|
15
30
|
|
16
|
-
it 'should
|
17
|
-
post.blog
|
31
|
+
it 'should provide accessors for association object' do
|
32
|
+
post.blog = blog
|
33
|
+
post.blog.should == blog
|
18
34
|
end
|
19
35
|
|
20
|
-
it 'should
|
21
|
-
post.
|
22
|
-
post.
|
36
|
+
it 'should set parent key(s) when setting association object' do
|
37
|
+
post.blog = blog
|
38
|
+
post.blog_subdomain.should == 'big-data'
|
23
39
|
end
|
24
40
|
|
25
|
-
it 'should
|
26
|
-
|
27
|
-
|
28
|
-
post.blog
|
41
|
+
it 'should raise ArgumentError when parent is set without keys' do
|
42
|
+
blog.subdomain = nil
|
43
|
+
expect { post.blog = blog }.to raise_error(ArgumentError)
|
29
44
|
end
|
30
45
|
|
31
|
-
it 'should
|
32
|
-
post.blog
|
33
|
-
|
34
|
-
connection.stub(:execute).
|
35
|
-
with('SELECT * FROM blogs WHERE ? = ? LIMIT 1', :id, 3).
|
36
|
-
and_return result_stub(:id => 2, :name => 'Another Blog')
|
46
|
+
it 'should raise ArgumentError when parent is set to wrong class' do
|
47
|
+
expect { post.blog = post }.to raise_error(ArgumentError)
|
48
|
+
end
|
37
49
|
|
38
|
-
|
50
|
+
it 'should return Blog instance when parent key set directly' do
|
51
|
+
post.blog_subdomain = 'big-data'
|
52
|
+
post.blog.subdomain.should == 'big-data'
|
39
53
|
end
|
40
54
|
|
41
|
-
it 'should
|
42
|
-
post.
|
43
|
-
|
55
|
+
it 'should not hydrate parent instance when creating from key' do
|
56
|
+
post.blog_subdomain = 'big-data'
|
57
|
+
disallow_queries!
|
58
|
+
post.blog.should_not be_loaded
|
44
59
|
end
|
45
60
|
|
46
|
-
it 'should
|
47
|
-
|
48
|
-
|
49
|
-
|
61
|
+
it 'should not allow declaring belongs_to after key' do
|
62
|
+
expect do
|
63
|
+
Class.new(Cequel::Model::Base) do
|
64
|
+
key :permalink, :text
|
65
|
+
belongs_to :blog
|
66
|
+
end
|
67
|
+
end.to raise_error(Cequel::Model::InvalidRecordConfiguration)
|
50
68
|
end
|
51
69
|
|
52
|
-
it 'should
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
[3, true, 'This blog', now, now]
|
60
|
-
connection.stub(:execute).
|
61
|
-
with "INSERT INTO posts (?) VALUES (?)", ['id', 'blog_id'], [post.id, 3]
|
62
|
-
post.save
|
70
|
+
it 'should not allow declaring belongs_to more than once' do
|
71
|
+
expect do
|
72
|
+
Class.new(Cequel::Model::Base) do
|
73
|
+
belongs_to :blog
|
74
|
+
belongs_to :user
|
75
|
+
end
|
76
|
+
end.to raise_error(Cequel::Model::InvalidRecordConfiguration)
|
63
77
|
end
|
64
78
|
|
65
79
|
end
|
66
80
|
|
67
81
|
describe '::has_many' do
|
68
|
-
let(:blog)
|
69
|
-
|
82
|
+
let(:blog) { Blog.new { |blog| blog.subdomain = 'cequel' }.tap(&:save) }
|
83
|
+
let!(:posts) do
|
84
|
+
3.times.map do |i|
|
85
|
+
Post.new do |post|
|
86
|
+
post.blog = blog
|
87
|
+
post.id = CassandraCQL::UUID.new
|
88
|
+
post.title = "Post #{i}"
|
89
|
+
end.tap(&:save)
|
90
|
+
end
|
70
91
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
92
|
+
let!(:other_posts) do
|
93
|
+
3.times.map do |i|
|
94
|
+
Post.new do |post|
|
95
|
+
post.blog_subdomain = 'mycat'
|
96
|
+
post.id = CassandraCQL::UUID.new
|
97
|
+
post.title = "My Cat #{i}"
|
98
|
+
end.tap(&:save)
|
99
|
+
end
|
79
100
|
end
|
80
101
|
|
81
|
-
it 'should
|
82
|
-
blog.posts.map
|
83
|
-
['Cequel', 'Cequel revisited']
|
102
|
+
it 'should return scope of posts' do
|
103
|
+
blog.posts.map(&:title).should == ["Post 0", "Post 1", "Post 2"]
|
84
104
|
end
|
85
105
|
|
86
|
-
it 'should
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
blog.destroy
|
106
|
+
it 'should retain scope when hydrated multiple times' do
|
107
|
+
blog.posts.map(&:id)
|
108
|
+
disallow_queries!
|
109
|
+
blog.posts.map(&:title).should == ["Post 0", "Post 1", "Post 2"]
|
91
110
|
end
|
92
|
-
end
|
93
|
-
|
94
|
-
describe '::has_one' do
|
95
|
-
let(:post) { Post.new(:id => 1) }
|
96
111
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
{:id => 1, :type => 'Photo', :url => 'http://outofti.me/glamour.jpg'},
|
102
|
-
)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should look up association by foreign key' do
|
106
|
-
post.thumbnail.url.should == 'http://outofti.me/glamour.jpg'
|
112
|
+
it 'should reload when reload argument passed' do
|
113
|
+
blog.posts.map(&:id)
|
114
|
+
posts.first.destroy
|
115
|
+
blog.posts(true).map(&:title).should == ['Post 1', 'Post 2']
|
107
116
|
end
|
108
117
|
end
|
118
|
+
|
109
119
|
end
|
@@ -1,79 +1,86 @@
|
|
1
1
|
require File.expand_path('../spec_helper', __FILE__)
|
2
2
|
|
3
3
|
describe Cequel::Model::Callbacks do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
model :Post do
|
5
|
+
key :permalink, :text
|
6
|
+
column :title, :text
|
7
|
+
|
8
|
+
def self.track_callbacks(*events)
|
9
|
+
events.each do |event|
|
10
|
+
%w(before after).each do |position|
|
11
|
+
callback_name = :"#{position}_#{event}"
|
12
|
+
__send__(callback_name) do |post|
|
13
|
+
post.executed_callbacks << callback_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
post.should have_callback(:save)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should invoke create callback' do
|
23
|
-
post.should have_callback(:create)
|
24
|
-
end
|
19
|
+
track_callbacks :save, :create, :update, :destroy
|
25
20
|
|
26
|
-
|
27
|
-
|
21
|
+
def executed_callbacks
|
22
|
+
@executed_callbacks ||= []
|
28
23
|
end
|
29
24
|
|
30
|
-
it 'should not invoke destroy callback' do
|
31
|
-
post.should_not have_callback(:destroy)
|
32
|
-
end
|
33
25
|
end
|
34
26
|
|
35
|
-
|
36
|
-
|
37
|
-
post.
|
38
|
-
|
39
|
-
|
40
|
-
it 'should invoke save callback' do
|
41
|
-
post.should have_callback(:save)
|
27
|
+
let(:new_post) do
|
28
|
+
Post.new do |post|
|
29
|
+
post.permalink = 'new-post'
|
30
|
+
post.title = 'New Post'
|
42
31
|
end
|
32
|
+
end
|
43
33
|
|
44
|
-
|
45
|
-
|
34
|
+
let!(:existing_post) do
|
35
|
+
Post.new do |post|
|
36
|
+
post.permalink = 'existing-post'
|
37
|
+
post.title = 'Existing Post'
|
38
|
+
end.save!
|
39
|
+
Post.find('existing-post').tap do |post|
|
40
|
+
post.title = 'An Existing Post'
|
46
41
|
end
|
42
|
+
end
|
47
43
|
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
context 'on create' do
|
45
|
+
before { new_post.save! }
|
46
|
+
subject { new_post.executed_callbacks }
|
47
|
+
|
48
|
+
it { should include(:before_save) }
|
49
|
+
it { should include(:after_save) }
|
50
|
+
it { should include(:before_create) }
|
51
|
+
it { should include(:after_create) }
|
52
|
+
it { should_not include(:before_update) }
|
53
|
+
it { should_not include(:after_update) }
|
54
|
+
it { should_not include(:before_destroy) }
|
55
|
+
it { should_not include(:after_destroy) }
|
56
|
+
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
context 'on update' do
|
59
|
+
before { existing_post.save! }
|
60
|
+
subject { existing_post.executed_callbacks }
|
61
|
+
|
62
|
+
it { should include(:before_save) }
|
63
|
+
it { should include(:after_save) }
|
64
|
+
it { should_not include(:before_create) }
|
65
|
+
it { should_not include(:after_create) }
|
66
|
+
it { should include(:before_update) }
|
67
|
+
it { should include(:after_update) }
|
68
|
+
it { should_not include(:before_destroy) }
|
69
|
+
it { should_not include(:after_destroy) }
|
55
70
|
end
|
56
71
|
|
57
72
|
context 'on destroy' do
|
58
|
-
before
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
it
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
it
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
it 'should not invoke update callback' do
|
72
|
-
post.should_not have_callback(:update)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'should invoke destroy callback' do
|
76
|
-
post.should have_callback(:destroy)
|
77
|
-
end
|
73
|
+
before { existing_post.destroy }
|
74
|
+
|
75
|
+
subject { existing_post.executed_callbacks }
|
76
|
+
|
77
|
+
it { should_not include(:before_save) }
|
78
|
+
it { should_not include(:after_save) }
|
79
|
+
it { should_not include(:before_create) }
|
80
|
+
it { should_not include(:after_create) }
|
81
|
+
it { should_not include(:before_update) }
|
82
|
+
it { should_not include(:after_update) }
|
83
|
+
it { should include(:before_destroy) }
|
84
|
+
it { should include(:after_destroy) }
|
78
85
|
end
|
79
86
|
end
|
@@ -0,0 +1,393 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Cequel::Model::List do
|
4
|
+
model :Post do
|
5
|
+
key :permalink, :text
|
6
|
+
column :title, :text
|
7
|
+
list :tags, :text
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:scope) { cequel[:posts].where(:permalink => 'cequel') }
|
11
|
+
subject { scope.first }
|
12
|
+
|
13
|
+
let! :post do
|
14
|
+
Post.new do |post|
|
15
|
+
post.permalink = 'cequel'
|
16
|
+
post.tags = %w(one two)
|
17
|
+
end.tap(&:save)
|
18
|
+
end
|
19
|
+
|
20
|
+
let! :unloaded_post do
|
21
|
+
Post['cequel']
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'new record' do
|
25
|
+
it 'should save list as-is' do
|
26
|
+
subject[:tags].should == %w(one two)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#<<' do
|
31
|
+
it 'should add new items' do
|
32
|
+
post.tags << 'three' << 'four'
|
33
|
+
post.save
|
34
|
+
subject[:tags].should == %w(one two three four)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should add new items atomically' do
|
38
|
+
scope.list_append(:tags, 'three')
|
39
|
+
post.tags << 'four' << 'five'
|
40
|
+
post.save
|
41
|
+
subject[:tags].should == %w(one two three four five)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should add new items without reading' do
|
45
|
+
unloaded_post.tags << 'four' << 'five'
|
46
|
+
unloaded_post.save
|
47
|
+
unloaded_post.should_not be_loaded
|
48
|
+
subject[:tags].should == %w(one two four five)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should add new items in memory when loaded' do
|
52
|
+
unloaded_post.tags << 'four' << 'five'
|
53
|
+
unloaded_post.tags.should == %w(one two four five)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#[]=' do
|
58
|
+
before { scope.list_append(:tags, 'three') }
|
59
|
+
|
60
|
+
it 'should atomically replace a single element' do
|
61
|
+
post.tags[1] = 'TWO'
|
62
|
+
post.save
|
63
|
+
subject[:tags].should == %w(one TWO three)
|
64
|
+
post.tags.should == %w(one TWO)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should replace an element without reading' do
|
68
|
+
cequel.should_not_receive :execute
|
69
|
+
unloaded_post.tags[1] = 'TWO'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should persist the replaced element' do
|
73
|
+
unloaded_post.tags[1] = 'TWO'
|
74
|
+
unloaded_post.save
|
75
|
+
subject[:tags].should == %w(one TWO three)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should apply local modifications when loaded later' do
|
79
|
+
unloaded_post.tags[1] = 'TWO'
|
80
|
+
unloaded_post.tags.should == %w(one TWO three)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should atomically replace a given number of arguments' do
|
84
|
+
post.tags[0, 2] = 'One', 'Two'
|
85
|
+
post.save
|
86
|
+
subject[:tags].should == %w(One Two three)
|
87
|
+
post.tags.should == %w(One Two)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should remove elements beyond positional arguments' do
|
91
|
+
scope.list_append(:tags, 'four')
|
92
|
+
post.tags[0, 3] = 'ONE'
|
93
|
+
post.save
|
94
|
+
subject[:tags].should == %w(ONE four)
|
95
|
+
post.tags.should == %w(ONE)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should atomically replace a given range of elements' do
|
99
|
+
post.tags[0..1] = ['One', 'Two']
|
100
|
+
post.save
|
101
|
+
subject[:tags].should == %w(One Two three)
|
102
|
+
post.tags.should == %w(One Two)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should remove elements beyond positional arguments' do
|
106
|
+
scope.list_append(:tags, 'four')
|
107
|
+
post.tags[0..2] = 'ONE'
|
108
|
+
post.save
|
109
|
+
subject[:tags].should == %w(ONE four)
|
110
|
+
post.tags.should == %w(ONE)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#clear' do
|
115
|
+
it 'should clear all elements from the array' do
|
116
|
+
post.tags.clear
|
117
|
+
post.save
|
118
|
+
subject[:tags].should be_blank
|
119
|
+
post.tags.should == []
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should clear elements without loading' do
|
123
|
+
cequel.should_not receive(:execute)
|
124
|
+
unloaded_post.tags.clear
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should persist clear without loading' do
|
128
|
+
unloaded_post.tags.clear
|
129
|
+
unloaded_post.save
|
130
|
+
subject[:tags].should be_blank
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should apply local modifications post-hoc' do
|
134
|
+
unloaded_post.tags.clear
|
135
|
+
unloaded_post.tags.should == []
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#collect!' do
|
140
|
+
it 'should not respond' do
|
141
|
+
expect { post.tags.collect!(&:upcase) }.to raise_error(NoMethodError)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe '#concat' do
|
146
|
+
it 'should atomically concatenate elements' do
|
147
|
+
scope.list_append(:tags, 'three')
|
148
|
+
post.tags.concat(['four', 'five'])
|
149
|
+
post.save
|
150
|
+
subject[:tags].should == %w(one two three four five)
|
151
|
+
post.tags.should == %w(one two four five)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should concat elements without loading' do
|
155
|
+
cequel.should_not_receive :execute
|
156
|
+
unloaded_post.tags.concat(['four', 'five'])
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should persist concatenated elements' do
|
160
|
+
unloaded_post.tags.concat(['four', 'five'])
|
161
|
+
unloaded_post.save
|
162
|
+
subject[:tags].should == %w(one two four five)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should apply local modifications when loaded later' do
|
166
|
+
unloaded_post.tags.concat(['four', 'five'])
|
167
|
+
unloaded_post.tags.should == %w(one two four five)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#delete' do
|
172
|
+
it 'should atomically delete all instances of an object' do
|
173
|
+
scope.list_append(:tags, 'three')
|
174
|
+
scope.list_append(:tags, 'two')
|
175
|
+
post.tags.delete('two')
|
176
|
+
post.save
|
177
|
+
subject[:tags].should == %w(one three)
|
178
|
+
post.tags.should == %w(one)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should delete without loading' do
|
182
|
+
cequel.should_not_receive :execute
|
183
|
+
unloaded_post.tags.delete('two')
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should persist deletions without loading' do
|
187
|
+
unloaded_post.tags.delete('two')
|
188
|
+
unloaded_post.save
|
189
|
+
subject[:tags].should == %w(one)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should modify local copy after the fact' do
|
193
|
+
unloaded_post.tags.delete('two')
|
194
|
+
unloaded_post.tags.should == %w(one)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe '#delete_at' do
|
199
|
+
it 'should atomically delete from a given index' do
|
200
|
+
scope.list_append(:tags, ['three', 'four'])
|
201
|
+
post.tags.delete_at(1)
|
202
|
+
post.save
|
203
|
+
subject[:tags].should == %w(one three four)
|
204
|
+
post.tags.should == %w(one)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should delete from a given index without reading' do
|
208
|
+
cequel.should_not_receive :execute
|
209
|
+
unloaded_post.tags.delete_at(1)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should persist deletion from unloaded list' do
|
213
|
+
unloaded_post.tags.delete_at(1)
|
214
|
+
unloaded_post.save
|
215
|
+
subject[:tags].should == %w(one)
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should apply deletion after the fact' do
|
219
|
+
unloaded_post.tags.delete_at(1)
|
220
|
+
unloaded_post.tags.should == %w(one)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '#delete_if' do
|
225
|
+
it 'should not respond' do
|
226
|
+
expect { post.tags.delete_if { |tag| tag.start_with?('o') } }.
|
227
|
+
to raise_error(NoMethodError)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe '#fill' do
|
232
|
+
it 'should not respond' do
|
233
|
+
expect { post.tags.fill('seventy') }.to raise_error(NoMethodError)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe '#flatten!' do
|
238
|
+
it 'should not respond' do
|
239
|
+
expect { post.tags.flatten! }.to raise_error(NoMethodError)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#insert' do
|
244
|
+
it 'should not respond' do
|
245
|
+
expect { post.tags.insert(4, 'five') }.to raise_error(NoMethodError)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
describe '#keep_if' do
|
250
|
+
it 'should not respond' do
|
251
|
+
expect { post.tags.keep_if { |e| e.start_with?('o') } }.
|
252
|
+
to raise_error(NoMethodError)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe '#map!' do
|
257
|
+
it 'should not respond' do
|
258
|
+
expect { post.tags.map! { |e| e.upcase } }.
|
259
|
+
to raise_error(NoMethodError)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe '#pop' do
|
264
|
+
it 'should not respond' do
|
265
|
+
expect { post.tags.pop }.to raise_error(NoMethodError)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#push' do
|
270
|
+
it 'should add new items atomically' do
|
271
|
+
scope.list_append(:tags, 'three')
|
272
|
+
post.tags.push('four').push('five')
|
273
|
+
post.save
|
274
|
+
subject[:tags].should == %w(one two three four five)
|
275
|
+
post.tags.should == %w(one two four five)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe '#reject!' do
|
280
|
+
it 'should not respond' do
|
281
|
+
expect { post.tags.reject! { |e| e.start_with?('o') } }.
|
282
|
+
to raise_error(NoMethodError)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe '#replace' do
|
287
|
+
it 'should just overwrite the whole array' do
|
288
|
+
scope.list_append(:tags, 'three')
|
289
|
+
post.tags.replace(%w(four five))
|
290
|
+
post.save
|
291
|
+
subject[:tags].should == %w(four five)
|
292
|
+
post.tags.should == %w(four five)
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'should overwrite without reading' do
|
296
|
+
cequel.should_not_receive :execute
|
297
|
+
unloaded_post.tags.replace(%w(four five))
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should persist unloaded overwrite' do
|
301
|
+
unloaded_post.tags.replace(%w(four five))
|
302
|
+
unloaded_post.save
|
303
|
+
subject[:tags].should == %w(four five)
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'should apply replace post-hoc' do
|
307
|
+
unloaded_post.tags.replace(%w(four five))
|
308
|
+
unloaded_post.tags.should == %w(four five)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe '#reverse!' do
|
313
|
+
it 'should not respond' do
|
314
|
+
expect { post.tags.reverse! }.to raise_error(NoMethodError)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe '#rotate!' do
|
319
|
+
it 'should not respond' do
|
320
|
+
expect { post.tags.rotate! }.to raise_error(NoMethodError)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe '#select!' do
|
325
|
+
it 'should not respond' do
|
326
|
+
expect { post.tags.select! { |e| e.start_with?('o') } }.
|
327
|
+
to raise_error(NoMethodError)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe '#shift' do
|
332
|
+
it 'should not respond' do
|
333
|
+
expect { post.tags.shift }.to raise_error(NoMethodError)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe '#shuffle!' do
|
338
|
+
it 'should not respond' do
|
339
|
+
expect { post.tags.shuffle! }.to raise_error(NoMethodError)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
describe '#slice!' do
|
344
|
+
it 'should not respond' do
|
345
|
+
expect { post.tags.slice!(1, 2) }.to raise_error(NoMethodError)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
describe '#sort!' do
|
350
|
+
it 'should not respond' do
|
351
|
+
expect { post.tags.sort! }.to raise_error(NoMethodError)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe '#sort_by!' do
|
356
|
+
it 'should not respond' do
|
357
|
+
expect { post.tags.sort_by! { |e| e.reverse } }.
|
358
|
+
to raise_error(NoMethodError)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe '#uniq!' do
|
363
|
+
it 'should not respond' do
|
364
|
+
expect { post.tags.uniq! }.to raise_error(NoMethodError)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe '#unshift' do
|
369
|
+
it 'should atomically unshift' do
|
370
|
+
scope.list_prepend(:tags, 'zero')
|
371
|
+
post.tags.unshift('minustwo', 'minusone')
|
372
|
+
post.save
|
373
|
+
subject[:tags].should == %w(minustwo minusone zero one two)
|
374
|
+
post.tags.should == %w(minustwo minusone one two)
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'should unshift without reading' do
|
378
|
+
cequel.should_not_receive :execute
|
379
|
+
unloaded_post.tags.unshift('minustwo', 'minusone')
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'should persist unloaded unshift' do
|
383
|
+
unloaded_post.tags.unshift('minustwo', 'minusone')
|
384
|
+
unloaded_post.save
|
385
|
+
subject[:tags].should == %w(minustwo minusone one two)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'should apply unshift after the fact' do
|
389
|
+
unloaded_post.tags.unshift('minustwo', 'minusone')
|
390
|
+
unloaded_post.tags.should == %w(minustwo minusone one two)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|