spec/extensions/static_cache_spec.rb in sequel-4.1.1 vs spec/extensions/static_cache_spec.rb in sequel-4.2.0
- old
+ new
@@ -1,195 +1,355 @@
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
-describe "Sequel::Plugins::StaticCache" do
+describe "Sequel::Plugins::StaticCache with :frozen=>false option" do
before do
@db = Sequel.mock
@db.fetch = [{:id=>1}, {:id=>2}]
+ @db.numrows = 1
@c = Class.new(Sequel::Model(@db[:t]))
- @c.columns :id
- @c.plugin :static_cache
- @c1 = @c.cache[1]
- @c2 = @c.cache[2]
- @db.sqls
+ @c.columns :id, :name
end
- it "should use a ruby hash as a cache of all model instances" do
- @c.cache.should == {1=>@c.load(:id=>1), 2=>@c.load(:id=>2)}
- end
+ shared_examples_for "Sequel::Plugins::StaticCache" do
+ it "should use a ruby hash as a cache of all model instances" do
+ @c.cache.should == {1=>@c.load(:id=>1), 2=>@c.load(:id=>2)}
+ @c.cache[1].should equal(@c1)
+ @c.cache[2].should equal(@c2)
+ end
- it "should work correctly with composite keys" do
- @db.fetch = [{:id=>1, :id2=>1}, {:id=>2, :id2=>1}]
- @c = Class.new(Sequel::Model(@db[:t]))
- @c.columns :id, :id2
- @c.set_primary_key([:id, :id2])
- @c.plugin :static_cache
- @db.sqls
- @c1 = @c.cache[[1, 2]]
- @c2 = @c.cache[[2, 1]]
- @c[[1, 2]].should equal(@c1)
- @c[[2, 1]].should equal(@c2)
- @db.sqls.should == []
- end
+ it "should make .[] method with primary key use the cache" do
+ @c[1].should == @c1
+ @c[2].should == @c2
+ @c[3].should be_nil
+ @c[[1, 2]].should be_nil
+ @c[nil].should be_nil
+ @c[].should be_nil
+ @db.sqls.should == []
+ end
- it "should make .[] method with primary key use the cache" do
- @c[1].should equal(@c1)
- @c[2].should equal(@c2)
- @c[3].should be_nil
- @c[[1, 2]].should be_nil
- @c[nil].should be_nil
- @c[].should be_nil
- @db.sqls.should == []
- end
+ it "should have .[] with a hash not use the cache" do
+ @db.fetch = {:id=>2}
+ @c[:id=>2].should == @c2
+ @db.sqls.should == ['SELECT * FROM t WHERE (id = 2) LIMIT 1']
+ end
- it "should have .[] with a hash not use the cache" do
- @db.fetch = {:id=>2}
- @c[:id=>2].should == @c2
- @db.sqls.should == ['SELECT * FROM t WHERE (id = 2) LIMIT 1']
- end
+ it "should support cache_get_pk" do
+ @c.cache_get_pk(1).should == @c1
+ @c.cache_get_pk(2).should == @c2
+ @c.cache_get_pk(3).should be_nil
+ @db.sqls.should == []
+ end
- it "should support cache_get_pk" do
- @c.cache_get_pk(1).should equal(@c1)
- @c.cache_get_pk(2).should equal(@c2)
- @c.cache_get_pk(3).should be_nil
- @db.sqls.should == []
- end
+ it "should have each just iterate over the hash's values without sending a query" do
+ a = []
+ @c.each{|o| a << o}
+ a = a.sort_by{|o| o.id}
+ a.first.should == @c1
+ a.last.should == @c2
+ @db.sqls.should == []
+ end
- it "should have each just iterate over the hash's values without sending a query" do
- a = []
- @c.each{|o| a << o}
- a = a.sort_by{|o| o.id}
- a.first.should equal(@c1)
- a.last.should equal(@c2)
- @db.sqls.should == []
- end
+ it "should have map just iterate over the hash's values without sending a query if no argument is given" do
+ @c.map{|v| v.id}.sort.should == [1, 2]
+ @db.sqls.should == []
+ end
- it "should have map just iterate over the hash's values without sending a query if no argument is given" do
- @c.map{|v| v.id}.sort.should == [1, 2]
- @db.sqls.should == []
- end
+ it "should have count with no argument or block not issue a query" do
+ @c.count.should == 2
+ @db.sqls.should == []
+ end
- it "should have count with no argument or block not issue a query" do
- @c.count.should == 2
- @db.sqls.should == []
- end
+ it "should have count with argument or block not issue a query" do
+ @db.fetch = [[{:count=>1}], [{:count=>2}]]
+ @c.count(:a).should == 1
+ @c.count{b}.should == 2
+ @db.sqls.should == ["SELECT count(a) AS count FROM t LIMIT 1", "SELECT count(b) AS count FROM t LIMIT 1"]
+ end
- it "should have count with argument or block not issue a query" do
- @db.fetch = [[{:count=>1}], [{:count=>2}]]
- @c.count(:a).should == 1
- @c.count{b}.should == 2
- @db.sqls.should == ["SELECT count(a) AS count FROM t LIMIT 1", "SELECT count(b) AS count FROM t LIMIT 1"]
- end
+ it "should have map not send a query if given an argument" do
+ @c.map(:id).sort.should == [1, 2]
+ @db.sqls.should == []
+ @c.map([:id,:id]).sort.should == [[1,1], [2,2]]
+ @db.sqls.should == []
+ end
- it "should have map not send a query if given an argument" do
- @c.map(:id).sort.should == [1, 2]
- @db.sqls.should == []
- @c.map([:id,:id]).sort.should == [[1,1], [2,2]]
- @db.sqls.should == []
- end
+ it "should have map without a block or argument not raise an exception or issue a query" do
+ @c.map.to_a.should == @c.all
+ @db.sqls.should == []
+ end
- it "should have map without a block or argument not raise an exception or issue a query" do
- @c.map.to_a.should == @c.all
- @db.sqls.should == []
- end
+ it "should have map without a block not return a frozen object" do
+ @c.map.frozen?.should be_false
+ end
- it "should have map without a block not return a frozen object" do
- @c.map.frozen?.should be_false
- end
+ it "should have map with a block and argument raise" do
+ proc{@c.map(:id){}}.should raise_error(Sequel::Error)
+ end
- it "should have map with a block and argument raise" do
- proc{@c.map(:id){}}.should raise_error(Sequel::Error)
- end
+ it "should have other enumerable methods work without sending a query" do
+ a = @c.sort_by{|o| o.id}
+ a.first.should == @c1
+ a.last.should == @c2
+ @db.sqls.should == []
+ end
- it "should have other enumerable methods work without sending a query" do
- a = @c.sort_by{|o| o.id}
- a.first.should equal(@c1)
- a.last.should equal(@c2)
- @db.sqls.should == []
- end
+ it "should have all return all objects" do
+ a = @c.all.sort_by{|o| o.id}
+ a.first.should == @c1
+ a.last.should == @c2
+ @db.sqls.should == []
+ end
- it "should have all just return the cached values" do
- a = @c.all.sort_by{|o| o.id}
- a.first.should equal(@c1)
- a.last.should equal(@c2)
- @db.sqls.should == []
- end
+ it "should have all not return a frozen object" do
+ @c.all.frozen?.should be_false
+ end
- it "should have all not return a frozen object" do
- @c.all.frozen?.should be_false
- end
+ it "should have all return things in dataset order" do
+ @c.all.should == [@c1, @c2]
+ end
- it "should have all return things in dataset order" do
- @c.all.should == [@c1, @c2]
- end
+ it "should have to_hash without arguments run without a query" do
+ a = @c.to_hash
+ a.should == {1=>@c1, 2=>@c2}
+ a[1].should == @c1
+ a[2].should == @c2
+ @db.sqls.should == []
+ end
- it "should have to_hash without arguments return the cached objects without a query" do
- a = @c.to_hash
- a.should == {1=>@c1, 2=>@c2}
- a[1].should equal(@c1)
- a[2].should equal(@c2)
- @db.sqls.should == []
- end
+ it "should have to_hash with arguments return results without a query" do
+ a = @c.to_hash(:id)
+ a.should == {1=>@c1, 2=>@c2}
+ a[1].should == @c1
+ a[2].should == @c2
- it "should have to_hash with arguments return the cached objects without a query" do
- a = @c.to_hash(:id)
- a.should == {1=>@c1, 2=>@c2}
- a[1].should equal(@c1)
- a[2].should equal(@c2)
+ a = @c.to_hash([:id])
+ a.should == {[1]=>@c1, [2]=>@c2}
+ a[[1]].should == @c1
+ a[[2]].should == @c2
- a = @c.to_hash([:id])
- a.should == {[1]=>@c1, [2]=>@c2}
- a[[1]].should equal(@c1)
- a[[2]].should equal(@c2)
+ @c.to_hash(:id, :id).should == {1=>1, 2=>2}
+ @c.to_hash([:id], :id).should == {[1]=>1, [2]=>2}
+ @c.to_hash(:id, [:id]).should == {1=>[1], 2=>[2]}
+ @c.to_hash([:id], [:id]).should == {[1]=>[1], [2]=>[2]}
- @c.to_hash(:id, :id).should == {1=>1, 2=>2}
- @c.to_hash([:id], :id).should == {[1]=>1, [2]=>2}
- @c.to_hash(:id, [:id]).should == {1=>[1], 2=>[2]}
- @c.to_hash([:id], [:id]).should == {[1]=>[1], [2]=>[2]}
+ @db.sqls.should == []
+ end
- @db.sqls.should == []
- end
+ it "should have to_hash not return a frozen object" do
+ @c.to_hash.frozen?.should be_false
+ end
- it "should have to_hash not return a frozen object" do
- @c.to_hash.frozen?.should be_false
- end
+ it "should have to_hash_groups without arguments return the cached objects without a query" do
+ a = @c.to_hash_groups(:id)
+ a.should == {1=>[@c1], 2=>[@c2]}
+ a[1].first.should == @c1
+ a[2].first.should == @c2
- it "should have to_hash_groups without arguments return the cached objects without a query" do
- a = @c.to_hash_groups(:id)
- a.should == {1=>[@c1], 2=>[@c2]}
- a[1].first.should equal(@c1)
- a[2].first.should equal(@c2)
+ a = @c.to_hash_groups([:id])
+ a.should == {[1]=>[@c1], [2]=>[@c2]}
+ a[[1]].first.should == @c1
+ a[[2]].first.should == @c2
- a = @c.to_hash_groups([:id])
- a.should == {[1]=>[@c1], [2]=>[@c2]}
- a[[1]].first.should equal(@c1)
- a[[2]].first.should equal(@c2)
+ @c.to_hash_groups(:id, :id).should == {1=>[1], 2=>[2]}
+ @c.to_hash_groups([:id], :id).should == {[1]=>[1], [2]=>[2]}
+ @c.to_hash_groups(:id, [:id]).should == {1=>[[1]], 2=>[[2]]}
+ @c.to_hash_groups([:id], [:id]).should == {[1]=>[[1]], [2]=>[[2]]}
- @c.to_hash_groups(:id, :id).should == {1=>[1], 2=>[2]}
- @c.to_hash_groups([:id], :id).should == {[1]=>[1], [2]=>[2]}
- @c.to_hash_groups(:id, [:id]).should == {1=>[[1]], 2=>[[2]]}
- @c.to_hash_groups([:id], [:id]).should == {[1]=>[[1]], [2]=>[[2]]}
+ @db.sqls.should == []
+ end
- @db.sqls.should == []
- end
+ it "subclasses should work correctly" do
+ c = Class.new(@c)
+ c.all.should == [c.load(:id=>1), c.load(:id=>2)]
+ c.to_hash.should == {1=>c.load(:id=>1), 2=>c.load(:id=>2)}
+ @db.sqls.should == ['SELECT * FROM t']
+ end
- it "all of the static cache values (model instances) should be frozen" do
- @c.all.all?{|o| o.frozen?}.should be_true
+ it "set_dataset should work correctly" do
+ ds = @c.dataset.from(:t2)
+ ds.instance_variable_set(:@columns, [:id])
+ ds._fetch = {:id=>3}
+ @c.dataset = ds
+ @c.all.should == [@c.load(:id=>3)]
+ @c.to_hash.should == {3=>@c.load(:id=>3)}
+ @c.to_hash[3].should == @c.all.first
+ @db.sqls.should == ['SELECT * FROM t2']
+ end
end
- it "subclasses should work correctly" do
- c = Class.new(@c)
- c.all.should == [c.load(:id=>1), c.load(:id=>2)]
- c.to_hash.should == {1=>c.load(:id=>1), 2=>c.load(:id=>2)}
- @db.sqls.should == ['SELECT * FROM t']
+ describe "without options" do
+ before do
+ @c.plugin :static_cache
+ @c1 = @c.cache[1]
+ @c2 = @c.cache[2]
+ @db.sqls
+ end
+
+ it_should_behave_like "Sequel::Plugins::StaticCache"
+
+ it "should work correctly with composite keys" do
+ @db.fetch = [{:id=>1, :id2=>1}, {:id=>2, :id2=>1}]
+ @c = Class.new(Sequel::Model(@db[:t]))
+ @c.columns :id, :id2
+ @c.set_primary_key([:id, :id2])
+ @c.plugin :static_cache
+ @db.sqls
+ @c1 = @c.cache[[1, 2]]
+ @c2 = @c.cache[[2, 1]]
+ @c[[1, 2]].should equal(@c1)
+ @c[[2, 1]].should equal(@c2)
+ @db.sqls.should == []
+ end
+
+ it "all of the static cache values (model instances) should be frozen" do
+ @c.all.all?{|o| o.frozen?}.should be_true
+ end
+
+ it "should make .[] method with primary key return cached instances" do
+ @c[1].should equal(@c1)
+ @c[2].should equal(@c2)
+ end
+
+ it "should have cache_get_pk return cached instances" do
+ @c.cache_get_pk(1).should equal(@c1)
+ @c.cache_get_pk(2).should equal(@c2)
+ end
+
+ it "should have each yield cached objects" do
+ a = []
+ @c.each{|o| a << o}
+ a = a.sort_by{|o| o.id}
+ a.first.should equal(@c1)
+ a.last.should equal(@c2)
+ end
+
+ it "should have other enumerable methods work yield cached objects" do
+ a = @c.sort_by{|o| o.id}
+ a.first.should equal(@c1)
+ a.last.should equal(@c2)
+ end
+
+ it "should have all return cached instances" do
+ a = @c.all.sort_by{|o| o.id}
+ a.first.should equal(@c1)
+ a.last.should equal(@c2)
+ end
+
+ it "should have to_hash without arguments use cached instances" do
+ a = @c.to_hash
+ a[1].should equal(@c1)
+ a[2].should equal(@c2)
+ end
+
+ it "should have to_hash with arguments return cached instances" do
+ a = @c.to_hash(:id)
+ a[1].should equal(@c1)
+ a[2].should equal(@c2)
+
+ a = @c.to_hash([:id])
+ a[[1]].should equal(@c1)
+ a[[2]].should equal(@c2)
+ end
+
+ it "should have to_hash_groups without single argument return the cached instances" do
+ a = @c.to_hash_groups(:id)
+ a[1].first.should equal(@c1)
+ a[2].first.should equal(@c2)
+
+ a = @c.to_hash_groups([:id])
+ a[[1]].first.should equal(@c1)
+ a[[2]].first.should equal(@c2)
+ end
+
+ it "should not allow the saving of new objects" do
+ proc{@c.create}.should raise_error(Sequel::BeforeHookFailed)
+ end
+
+ it "should not allow the saving of existing objects" do
+ @db.fetch = {:id=>1}
+ proc{@c.first(:id=>1).save}.should raise_error(Sequel::BeforeHookFailed)
+ end
+
+ it "should not allow the destroying of existing objects" do
+ @db.fetch = {:id=>1}
+ proc{@c.first(:id=>1).destroy}.should raise_error(Sequel::BeforeHookFailed)
+ end
end
- it "set_dataset should work correctly" do
- ds = @c.dataset.from(:t2)
- ds.instance_variable_set(:@columns, [:id])
- ds._fetch = {:id=>3}
- @c.dataset = ds
- @c.all.should == [@c.load(:id=>3)]
- @c.to_hash.should == {3=>@c.load(:id=>3)}
- @c.to_hash[3].should equal(@c.all.first)
- @db.sqls.should == ['SELECT * FROM t2']
+ describe "with :frozen=>false option" do
+ before do
+ @c.plugin :static_cache, :frozen=>false
+ @c1 = @c.cache[1]
+ @c2 = @c.cache[2]
+ @db.sqls
+ end
+
+ it_should_behave_like "Sequel::Plugins::StaticCache"
+
+ it "record retrieved by primary key should not be frozen" do
+ @c[1].frozen?.should be_false
+ @c.cache_get_pk(1).frozen?.should be_false
+ end
+
+ it "none of values returned in #all should be frozen" do
+ @c.all.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values yielded by each should be frozen" do
+ a = []
+ @c.each{|o| a << o}
+ a.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values yielded by Enumerable method should be frozen" do
+ @c.sort_by{|o| o.id}.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values returned by map without an argument or block should be frozen" do
+ @c.map{|o| o}.all?{|o| !o.frozen?}.should be_true
+ @c.map.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values in the hash returned by to_hash without an argument should be frozen" do
+ @c.to_hash.values.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values in the hash returned by to_hash with a single argument should be frozen" do
+ @c.to_hash(:id).values.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values in the hash returned by to_hash with a single array argument should be frozen" do
+ @c.to_hash([:id, :id]).values.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values in the hash returned by to_hash_groups with a single argument should be frozen" do
+ @c.to_hash_groups(:id).values.flatten.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "none of values in the hash returned by to_hash_groups with a single array argument should be frozen" do
+ @c.to_hash_groups([:id, :id]).values.flatten.all?{|o| !o.frozen?}.should be_true
+ end
+
+ it "should not automatically update the cache when creating new model objects" do
+ o = @c.new
+ o.id = 3
+ @db.autoid = 3
+ @db.fetch = [[{:id=>1}, {:id=>2}, {:id=>3}], [{:id=>3}]]
+ o.save
+ @c[3].should == nil
+ end
+
+ it "should not automatically update the cache when updating model objects" do
+ o = @c[2]
+ @db.fetch = [[{:id=>1}, {:id=>2, :name=>'a'}]]
+ o.update(:name=>'a')
+ @c[2].values.should == {:id=>2}
+ end
+
+ it "should not automatically update the cache when updating model objects" do
+ o = @c[2]
+ @db.fetch = [[{:id=>1}]]
+ o.destroy
+ @c[2].should == @c2
+ end
end
end