spec/integration/plugin_test.rb in sequel-3.12.1 vs spec/integration/plugin_test.rb in sequel-3.13.0

- old
+ new

@@ -1,6 +1,6 @@ -require File.join(File.dirname(__FILE__), 'spec_helper.rb') +require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb') # H2 and MSSQL don't support USING joins unless [:h2, :mssql].include?(INTEGRATION_DB.database_type) describe "Class Table Inheritance Plugin" do before do @@ -958,7 +958,322 @@ @db[:albums_tags].filter(:album_id=>@al3).select_order_map(:tag_id).should == [] Album[@al3].tag_pks = [@t1, @t3] @db[:albums_tags].filter(:album_id=>@al3).select_order_map(:tag_id).should == [@t1, @t3] Album[@al3].tag_pks = [] @db[:albums_tags].filter(:album_id=>@al1).select_order_map(:tag_id).should == [] + end +end + + +describe "List plugin without a scope" do + before do + @db = INTEGRATION_DB + @db.create_table :sites do + primary_key :id + String :name + Integer :position + end + + @c = Class.new(Sequel::Model(@db[:sites])) + @c.plugin :list + @c.delete + @c.create :name => "hig", :position => 3 + @c.create :name => "def", :position => 2 + @c.create :name => "abc", :position => 1 + end + + after do + @db.drop_table(:sites) + end + + it "should return rows in order of position" do + @c.map(:position).should == [1,2,3] + @c.map(:name).should == %w[ abc def hig ] + end + + it "should define prev and next" do + i = @c[:name => "abc"] + i.prev.should == nil + i = @c[:name => "def"] + i.prev.should == @c[:name => "abc"] + i.next.should == @c[:name => "hig"] + i = @c[:name => "hig"] + i.next.should == nil + end + + it "should define move_to" do + @c[:name => "def"].move_to(1) + @c.map(:name).should == %w[ def abc hig ] + + @c[:name => "abc"].move_to(3) + @c.map(:name).should == %w[ def hig abc ] + + proc { @c[:name => "abc"].move_to(-1) }.should raise_error(Sequel::Error) + proc { @c[:name => "abc"].move_to(10) }.should raise_error(Sequel::Error) + end + + it "should define move_to_top and move_to_bottom" do + @c[:name => "def"].move_to_top + @c.map(:name).should == %w[ def abc hig ] + + @c[:name => "def"].move_to_bottom + @c.map(:name).should == %w[ abc hig def ] + end + + it "should define move_up and move_down" do + @c[:name => "def"].move_up + @c.map(:name).should == %w[ def abc hig ] + + @c[:name => "abc"].move_down + @c.map(:name).should == %w[ def hig abc ] + + @c[:name => "abc"].move_up(2) + @c.map(:name).should == %w[ abc def hig ] + + @c[:name => "abc"].move_down(2) + @c.map(:name).should == %w[ def hig abc ] + + proc { @c[:name => "def"].move_up(10) }.should raise_error(Sequel::Error) + proc { @c[:name => "def"].move_down(10) }.should raise_error(Sequel::Error) + end +end + +describe "List plugin with a scope" do + before do + @db = INTEGRATION_DB + @db.create_table :pages do + primary_key :id + String :name + Integer :pos + Integer :parent_id + end + + @c = Class.new(Sequel::Model(@db[:pages])) + @c.plugin :list, :field => :pos, :scope => :parent_id + p1 = @c.create :name => "Hm", :pos => 1, :parent_id => 0 + p2 = @c.create :name => "Ps", :pos => 1, :parent_id => p1.id + @c.create :name => "P1", :pos => 1, :parent_id => p2.id + @c.create :name => "P2", :pos => 2, :parent_id => p2.id + @c.create :name => "P3", :pos => 3, :parent_id => p2.id + @c.create :name => "Au", :pos => 2, :parent_id => p1.id + end + + after do + @db.drop_table(:pages) + end + + it "should return rows in order of position" do + @c.map(:name).should == %w[ Hm Ps Au P1 P2 P3 ] + end + + it "should define prev and next" do + @c[:name => "Ps"].next.name.should == 'Au' + @c[:name => "Au"].prev.name.should == 'Ps' + @c[:name => "P1"].next.name.should == 'P2' + @c[:name => "P2"].prev.name.should == 'P1' + + @c[:name => "P1"].next(2).name.should == 'P3' + @c[:name => "P2"].next(-1).name.should == 'P1' + @c[:name => "P3"].prev(2).name.should == 'P1' + @c[:name => "P2"].prev(-1).name.should == 'P3' + + @c[:name => "Ps"].prev.should == nil + @c[:name => "Au"].next.should == nil + @c[:name => "P1"].prev.should == nil + @c[:name => "P3"].next.should == nil + end + + it "should define move_to" do + @c[:name => "P2"].move_to(1) + @c.map(:name).should == %w[ Hm Ps Au P2 P1 P3 ] + + @c[:name => "P2"].move_to(3) + @c.map(:name).should == %w[ Hm Ps Au P1 P3 P2 ] + + proc { @c[:name => "P2"].move_to(-1) }.should raise_error(Sequel::Error) + proc { @c[:name => "P2"].move_to(10) }.should raise_error(Sequel::Error) + end + + it "should define move_to_top and move_to_bottom" do + @c[:name => "Au"].move_to_top + @c.map(:name).should == %w[ Hm Au Ps P1 P2 P3 ] + + @c[:name => "Au"].move_to_bottom + @c.map(:name).should == %w[ Hm Ps Au P1 P2 P3 ] + end + + it "should define move_up and move_down" do + @c[:name => "P2"].move_up + @c.map(:name).should == %w[ Hm Ps Au P2 P1 P3 ] + + @c[:name => "P1"].move_down + @c.map(:name).should == %w[ Hm Ps Au P2 P3 P1 ] + + proc { @c[:name => "P1"].move_up(10) }.should raise_error(Sequel::Error) + proc { @c[:name => "P1"].move_down(10) }.should raise_error(Sequel::Error) + end +end + +describe "Sequel::Plugins::Tree" do + before do + @db = INTEGRATION_DB + end + + describe "with natural database order" do + before do + @db.create_table!(:nodes) do + Integer :id, :primary_key=>true + String :name + Integer :parent_id + Integer :position + end + + @nodes = [{:id => 1, :name => 'one', :parent_id => nil, :position => 1}, + {:id => 2, :name => 'two', :parent_id => nil, :position => 2}, + {:id => 3, :name => 'three', :parent_id => nil, :position => 3}, + {:id => 4, :name => "two.one", :parent_id => 2, :position => 1}, + {:id => 5, :name => "two.two", :parent_id => 2, :position => 2}, + {:id => 6, :name => "two.two.one", :parent_id => 5, :position => 1}, + {:id => 7, :name => "one.two", :parent_id => 1, :position => 2}, + {:id => 8, :name => "one.one", :parent_id => 1, :position => 1}, + {:id => 9, :name => "five", :parent_id => nil, :position => 5}, + {:id => 10, :name => "four", :parent_id => nil, :position => 4}, + {:id => 11, :name => "five.one", :parent_id => 9, :position => 1}, + {:id => 12, :name => "two.three", :parent_id => 2, :position => 3}] + @nodes.each{|node| @db[:nodes].insert(node)} + + class ::Node < Sequel::Model + plugin :tree + end + end + after do + @db.drop_table(:nodes) + Object.send(:remove_const, :Node) + end + + it "should instantiate" do + Node.all.size.should == 12 + end + + it "should find top level nodes" do + Node.roots_dataset.count.should == 5 + end + + it "should find all descendants of a node" do + two = Node.find(:id => 2) + two.name.should == "two" + two.descendants.map{|m| m[:id]}.should == [4, 5, 12, 6] + end + + it "should find all ancestors of a node" do + twotwoone = Node.find(:id => 6) + twotwoone.name.should == "two.two.one" + twotwoone.ancestors.map{|m| m[:id]}.should == [5, 2] + end + + it "should find all siblings of a node, excepting self" do + twoone = Node.find(:id => 4) + twoone.name.should == "two.one" + twoone.siblings.map{|m| m[:id]}.should == [5, 12] + end + + it "should find all siblings of a node, including self" do + twoone = Node.find(:id => 4) + twoone.name.should == "two.one" + twoone.self_and_siblings.map{|m| m[:id]}.should == [4, 5, 12] + end + + it "should find siblings for root nodes" do + three = Node.find(:id => 3) + three.name.should == "three" + three.self_and_siblings.map{|m| m[:id]}.should == [1, 2, 3, 9, 10] + end + + it "should find correct root for a node" do + twotwoone = Node.find(:id => 6) + twotwoone.name.should == "two.two.one" + twotwoone.root[:id].should == 2 + + three = Node.find(:id => 3) + three.name.should == "three" + three.root[:id].should == 3 + + fiveone = Node.find(:id => 11) + fiveone.name.should == "five.one" + fiveone.root[:id].should == 9 + end + + it "iterate top-level nodes in natural database order" do + Node.roots_dataset.count.should == 5 + Node.roots.inject([]){|ids, p| ids << p.position}.should == [1, 2, 3, 5, 4] + end + + it "should have children" do + one = Node.find(:id => 1) + one.name.should == "one" + one.children.size.should == 2 + end + + it "children should be natural database order" do + one = Node.find(:id => 1) + one.name.should == "one" + one.children.map{|m| m[:position]}.should == [2, 1] + end + + describe "Nodes in specified order" do + before do + class ::OrderedNode < Sequel::Model(:nodes) + plugin :tree, :order => :position + end + end + after do + Object.send(:remove_const, :OrderedNode) + end + + it "iterate top-level nodes in order by position" do + OrderedNode.roots_dataset.count.should == 5 + OrderedNode.roots.inject([]){|ids, p| ids << p.position}.should == [1, 2, 3, 4, 5] + end + + it "children should be in specified order" do + one = OrderedNode.find(:id => 1) + one.name.should == "one" + one.children.map{|m| m[:position]}.should == [1, 2] + end + end + end + + describe "Lorems in specified order" do + before do + @db.create_table!(:lorems) do + Integer :id, :primary_key=>true + String :name + Integer :ipsum_id + Integer :neque + end + + @lorems = [{:id => 1, :name => 'Lorem', :ipsum_id => nil, :neque => 4}, + {:id => 2, :name => 'Ipsum', :ipsum_id => nil, :neque => 3}, + {:id => 4, :name => "Neque", :ipsum_id => 2, :neque => 2}, + {:id => 5, :name => "Porro", :ipsum_id => 2, :neque => 1}] + @lorems.each{|lorem| @db[:lorems].insert(lorem)} + + class ::Lorem < Sequel::Model + plugin :tree, :key => :ipsum_id, :order => :neque + end + end + after do + @db.drop_table(:lorems) + Object.send(:remove_const, :Lorem) + end + + it "iterate top-level nodes in order by position" do + Lorem.roots_dataset.count.should == 2 + Lorem.roots.inject([]){|ids, p| ids << p.neque}.should == [3, 4] + end + + it "children should be specified order" do + one = Lorem.find(:id => 2) + one.children.map{|m| m[:neque]}.should == [1, 2] + end end end