sequel 4.2.0 → 4.3.0

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +28 -0
  3. data/doc/extensions.rdoc +84 -0
  4. data/doc/model_plugins.rdoc +270 -0
  5. data/doc/release_notes/4.3.0.txt +40 -0
  6. data/doc/testing.rdoc +3 -0
  7. data/lib/sequel/adapters/jdbc/as400.rb +4 -0
  8. data/lib/sequel/adapters/shared/mysql.rb +6 -1
  9. data/lib/sequel/adapters/shared/postgres.rb +2 -0
  10. data/lib/sequel/ast_transformer.rb +2 -0
  11. data/lib/sequel/extensions/error_sql.rb +71 -0
  12. data/lib/sequel/extensions/migration.rb +0 -1
  13. data/lib/sequel/extensions/pagination.rb +6 -2
  14. data/lib/sequel/extensions/pg_array.rb +12 -5
  15. data/lib/sequel/extensions/pg_hstore.rb +5 -3
  16. data/lib/sequel/extensions/pg_inet.rb +3 -3
  17. data/lib/sequel/extensions/pg_interval.rb +3 -3
  18. data/lib/sequel/extensions/pg_json.rb +3 -3
  19. data/lib/sequel/extensions/pg_range.rb +3 -3
  20. data/lib/sequel/extensions/pg_row.rb +3 -3
  21. data/lib/sequel/extensions/server_block.rb +11 -3
  22. data/lib/sequel/plugins/rcte_tree.rb +59 -39
  23. data/lib/sequel/plugins/tree.rb +13 -6
  24. data/lib/sequel/sql.rb +1 -1
  25. data/lib/sequel/version.rb +1 -1
  26. data/spec/adapters/postgres_spec.rb +17 -0
  27. data/spec/core/dataset_spec.rb +14 -0
  28. data/spec/core/schema_spec.rb +1 -0
  29. data/spec/extensions/error_sql_spec.rb +20 -0
  30. data/spec/extensions/migration_spec.rb +15 -0
  31. data/spec/extensions/pagination_spec.rb +19 -0
  32. data/spec/extensions/pg_array_spec.rb +3 -2
  33. data/spec/extensions/rcte_tree_spec.rb +135 -0
  34. data/spec/extensions/tree_spec.rb +130 -0
  35. data/spec/integration/database_test.rb +5 -0
  36. data/spec/integration/dataset_test.rb +4 -0
  37. data/spec/integration/plugin_test.rb +163 -177
  38. data/spec/integration/spec_helper.rb +4 -0
  39. metadata +10 -2
@@ -24,6 +24,11 @@ describe Sequel::Database do
24
24
  proc{@db << "SELECT"}.should raise_error(Sequel::DatabaseError)
25
25
  end
26
26
 
27
+ specify "should have Sequel::DatabaseError#sql give the SQL causing the error" do
28
+ (@db << "SELECT") rescue (e = $!)
29
+ e.sql.should == "SELECT"
30
+ end if ENV['SEQUEL_ERROR_SQL']
31
+
27
32
  describe "constraint violations" do
28
33
  before do
29
34
  @db.drop_table?(:test2, :test)
@@ -371,6 +371,10 @@ describe Sequel::Database do
371
371
  DB.get(Sequel.cast(Sequel.blob("\1\2\3"), File).as(:a)).should == "\1\2\3"
372
372
  end
373
373
 
374
+ cspecify "should properly handle empty blobs", [:jdbc, :hsqldb], :oracle do
375
+ DB.get(Sequel.cast(Sequel.blob(""), File).as(:a)).should == ""
376
+ end
377
+
374
378
  cspecify "should properly escape identifiers", :db2, :oracle do
375
379
  DB.create_table(:"\\'\"[]"){Integer :id}
376
380
  DB.drop_table(:"\\'\"[]")
@@ -705,43 +705,8 @@ describe "Composition plugin" do
705
705
  end
706
706
  end
707
707
 
708
- # DB2's implemention of CTE is too limited to use this plugin
709
- if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
710
- describe "RcteTree Plugin" do
711
- before(:all) do
712
- @db = DB
713
- @db.create_table!(:nodes) do
714
- primary_key :id
715
- Integer :parent_id
716
- String :name
717
- end
718
- class ::Node < Sequel::Model(@db)
719
- plugin :rcte_tree, :order=>:name
720
- end
721
-
722
- @nodes = []
723
- @nodes << @a = Node.create(:name=>'a')
724
- @nodes << @b = Node.create(:name=>'b')
725
- @nodes << @aa = Node.create(:name=>'aa', :parent=>@a)
726
- @nodes << @ab = Node.create(:name=>'ab', :parent=>@a)
727
- @nodes << @ba = Node.create(:name=>'ba', :parent=>@b)
728
- @nodes << @bb = Node.create(:name=>'bb', :parent=>@b)
729
- @nodes << @aaa = Node.create(:name=>'aaa', :parent=>@aa)
730
- @nodes << @aab = Node.create(:name=>'aab', :parent=>@aa)
731
- @nodes << @aba = Node.create(:name=>'aba', :parent=>@ab)
732
- @nodes << @abb = Node.create(:name=>'abb', :parent=>@ab)
733
- @nodes << @aaaa = Node.create(:name=>'aaaa', :parent=>@aaa)
734
- @nodes << @aaab = Node.create(:name=>'aaab', :parent=>@aaa)
735
- @nodes << @aaaaa = Node.create(:name=>'aaaaa', :parent=>@aaaa)
736
- end
737
- before do
738
- @nodes.each{|n| n.associations.clear}
739
- end
740
- after(:all) do
741
- @db.drop_table? :nodes
742
- Object.send(:remove_const, :Node)
743
- end
744
-
708
+ describe "RcteTree Plugin" do
709
+ shared_examples_for "rcte tree plugin" do
745
710
  specify "should load all standard (not-CTE) methods correctly" do
746
711
  @a.children.should == [@aa, @ab]
747
712
  @b.children.should == [@ba, @bb]
@@ -803,7 +768,7 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
803
768
  end
804
769
 
805
770
  specify "should eagerly load all ancestors and descendants for a dataset" do
806
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
771
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:ancestors, :descendants).all
807
772
  nodes.should == [@a, @aaa, @b]
808
773
  nodes[0].descendants.should == [@aa, @aaa, @aaaa, @aaaaa, @aaab, @aab, @ab, @aba, @abb]
809
774
  nodes[1].descendants.should == [@aaaa, @aaaaa, @aaab]
@@ -813,26 +778,14 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
813
778
  nodes[2].ancestors.should == []
814
779
  end
815
780
 
816
- specify "should work correctly if not all columns are selected" do
817
- c = Class.new(Sequel::Model(@db[:nodes]))
818
- c.plugin :rcte_tree, :order=>:name
819
- c.plugin :lazy_attributes, :name
820
- c[:name=>'aaaa'].descendants.should == [c.load(:parent_id=>11, :id=>13)]
821
- c[:name=>'aa'].ancestors.should == [c.load(:parent_id=>nil, :id=>1)]
822
- nodes = c.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
823
- nodes.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>3, :id=>7}, {:parent_id=>nil, :id=>2}].map{|x| c.load(x)}
824
- nodes[2].descendants.should == [{:parent_id=>2, :id=>5}, {:parent_id=>2, :id=>6}].map{|x| c.load(x)}
825
- nodes[1].ancestors.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>1, :id=>3}].map{|x| c.load(x)}
826
- end
827
-
828
781
  specify "should eagerly load descendants to a given level" do
829
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>1).all
782
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:descendants=>1).all
830
783
  nodes.should == [@a, @aaa, @b]
831
784
  nodes[0].descendants.should == [@aa, @ab]
832
785
  nodes[1].descendants.should == [@aaaa, @aaab]
833
786
  nodes[2].descendants.should == [@ba, @bb]
834
787
 
835
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>2).all
788
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:descendants=>2).all
836
789
  nodes.should == [@a, @aaa, @b]
837
790
  nodes[0].descendants.should == [@aa, @aaa, @aab, @ab, @aba, @abb]
838
791
  nodes[1].descendants.should == [@aaaa, @aaaaa, @aaab]
@@ -840,7 +793,7 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
840
793
  end
841
794
 
842
795
  specify "should populate all :children associations when eagerly loading descendants for a dataset" do
843
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants).all
796
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:descendants).all
844
797
  nodes[0].associations[:children].should == [@aa, @ab]
845
798
  nodes[1].associations[:children].should == [@aaaa, @aaab]
846
799
  nodes[2].associations[:children].should == [@ba, @bb]
@@ -854,7 +807,7 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
854
807
  end
855
808
 
856
809
  specify "should not populate :children associations for final level when loading descendants to a given level" do
857
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>1).all
810
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:descendants=>1).all
858
811
  nodes[0].associations[:children].should == [@aa, @ab]
859
812
  nodes[0].associations[:children].map{|c1| c1.associations[:children]}.should == [nil, nil]
860
813
  nodes[1].associations[:children].should == [@aaaa, @aaab]
@@ -866,7 +819,7 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
866
819
  nodes[1].associations[:children].map{|c1| c1.children}.should == [[@aaaaa], []]
867
820
  nodes[2].associations[:children].map{|c1| c1.children}.should == [[], []]
868
821
 
869
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>2).all
822
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @b.pk, @aaa.pk]).order(:name).eager(:descendants=>2).all
870
823
  nodes[0].associations[:children].should == [@aa, @ab]
871
824
  nodes[0].associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaa, @aab], [@aba, @abb]]
872
825
  nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@aaaa, @aaab], nil], [nil, nil]]
@@ -904,7 +857,7 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
904
857
  end
905
858
 
906
859
  specify "should populate all :parent associations when eagerly loading ancestors for a dataset" do
907
- nodes = Node.filter(:id=>[@a.id, @ba.id, @aaa.id, @aaaaa.id]).order(:name).eager(:ancestors).all
860
+ nodes = @Node.filter(@Node.primary_key=>[@a.pk, @ba.pk, @aaa.pk, @aaaaa.pk]).order(:name).eager(:ancestors).all
908
861
  nodes[0].associations.fetch(:parent, 1).should == nil
909
862
  nodes[1].associations[:parent].should == @aa
910
863
  nodes[1].associations[:parent].associations[:parent].should == @a
@@ -937,7 +890,91 @@ if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
937
890
  @aaaaa.associations[:parent].associations[:parent].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
938
891
  end
939
892
  end
940
- end
893
+
894
+ before do
895
+ @nodes.each{|n| n.associations.clear}
896
+ end
897
+
898
+ describe "with single key" do
899
+ before(:all) do
900
+ @db = DB
901
+ @db.create_table!(:nodes) do
902
+ primary_key :id
903
+ Integer :parent_id
904
+ String :name
905
+ end
906
+ @Node = Class.new(Sequel::Model(@db[:nodes]))
907
+ @Node.plugin :rcte_tree, :order=>:name
908
+ @nodes = []
909
+ @nodes << @a = @Node.create(:name=>'a')
910
+ @nodes << @b = @Node.create(:name=>'b')
911
+ @nodes << @aa = @Node.create(:name=>'aa', :parent=>@a)
912
+ @nodes << @ab = @Node.create(:name=>'ab', :parent=>@a)
913
+ @nodes << @ba = @Node.create(:name=>'ba', :parent=>@b)
914
+ @nodes << @bb = @Node.create(:name=>'bb', :parent=>@b)
915
+ @nodes << @aaa = @Node.create(:name=>'aaa', :parent=>@aa)
916
+ @nodes << @aab = @Node.create(:name=>'aab', :parent=>@aa)
917
+ @nodes << @aba = @Node.create(:name=>'aba', :parent=>@ab)
918
+ @nodes << @abb = @Node.create(:name=>'abb', :parent=>@ab)
919
+ @nodes << @aaaa = @Node.create(:name=>'aaaa', :parent=>@aaa)
920
+ @nodes << @aaab = @Node.create(:name=>'aaab', :parent=>@aaa)
921
+ @nodes << @aaaaa = @Node.create(:name=>'aaaaa', :parent=>@aaaa)
922
+ end
923
+ after(:all) do
924
+ @db.drop_table? :nodes
925
+ end
926
+
927
+ it_should_behave_like "rcte tree plugin"
928
+
929
+ specify "should work correctly if not all columns are selected" do
930
+ c = Class.new(Sequel::Model(@db[:nodes]))
931
+ c.plugin :rcte_tree, :order=>:name
932
+ c.plugin :lazy_attributes, :name
933
+ c[:name=>'aaaa'].descendants.should == [c.load(:parent_id=>11, :id=>13)]
934
+ c[:name=>'aa'].ancestors.should == [c.load(:parent_id=>nil, :id=>1)]
935
+ nodes = c.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
936
+ nodes.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>3, :id=>7}, {:parent_id=>nil, :id=>2}].map{|x| c.load(x)}
937
+ nodes[2].descendants.should == [{:parent_id=>2, :id=>5}, {:parent_id=>2, :id=>6}].map{|x| c.load(x)}
938
+ nodes[1].ancestors.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>1, :id=>3}].map{|x| c.load(x)}
939
+ end
940
+ end
941
+
942
+ describe "with composite keys" do
943
+ before(:all) do
944
+ @db = DB
945
+ @db.create_table!(:nodes) do
946
+ Integer :id
947
+ Integer :id2
948
+ Integer :parent_id
949
+ Integer :parent_id2
950
+ String :name
951
+ primary_key [:id, :id2]
952
+ end
953
+ @Node = Class.new(Sequel::Model(@db[:nodes]))
954
+ @Node.plugin :rcte_tree, :order=>:name, :key=>[:parent_id, :parent_id2]
955
+ @Node.unrestrict_primary_key
956
+ @nodes = []
957
+ @nodes << @a = @Node.create(:id=>1, :id2=>1, :name=>'a')
958
+ @nodes << @b = @Node.create(:id=>1, :id2=>2, :name=>'b')
959
+ @nodes << @aa = @Node.create(:id=>2, :id2=>1, :name=>'aa', :parent=>@a)
960
+ @nodes << @ab = @Node.create(:id=>2, :id2=>2, :name=>'ab', :parent=>@a)
961
+ @nodes << @ba = @Node.create(:id=>3, :id2=>1, :name=>'ba', :parent=>@b)
962
+ @nodes << @bb = @Node.create(:id=>3, :id2=>2, :name=>'bb', :parent=>@b)
963
+ @nodes << @aaa = @Node.create(:id=>3, :id2=>3, :name=>'aaa', :parent=>@aa)
964
+ @nodes << @aab = @Node.create(:id=>1, :id2=>3, :name=>'aab', :parent=>@aa)
965
+ @nodes << @aba = @Node.create(:id=>2, :id2=>3, :name=>'aba', :parent=>@ab)
966
+ @nodes << @abb = @Node.create(:id=>4, :id2=>1, :name=>'abb', :parent=>@ab)
967
+ @nodes << @aaaa = @Node.create(:id=>1, :id2=>4, :name=>'aaaa', :parent=>@aaa)
968
+ @nodes << @aaab = @Node.create(:id=>2, :id2=>4, :name=>'aaab', :parent=>@aaa)
969
+ @nodes << @aaaaa = @Node.create(:id=>3, :id2=>4, :name=>'aaaaa', :parent=>@aaaa)
970
+ end
971
+ after(:all) do
972
+ @db.drop_table? :nodes
973
+ end
974
+
975
+ it_should_behave_like "rcte tree plugin"
976
+ end
977
+ end if DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
941
978
 
942
979
  describe "Instance Filters plugin" do
943
980
  before(:all) do
@@ -1538,167 +1575,116 @@ describe "List plugin with a scope" do
1538
1575
  end
1539
1576
 
1540
1577
  describe "Sequel::Plugins::Tree" do
1541
- before(:all) do
1542
- @db = DB
1543
- end
1544
-
1545
- describe "with natural database order" do
1546
- before(:all) do
1547
- @db.create_table!(:nodes) do
1548
- Integer :id, :primary_key=>true
1549
- String :name
1550
- Integer :parent_id
1551
- Integer :position
1552
- end
1553
-
1554
- @nodes = [{:id => 1, :name => 'one', :parent_id => nil, :position => 1},
1555
- {:id => 2, :name => 'two', :parent_id => nil, :position => 2},
1556
- {:id => 3, :name => 'three', :parent_id => nil, :position => 3},
1557
- {:id => 4, :name => "two.one", :parent_id => 2, :position => 1},
1558
- {:id => 5, :name => "two.two", :parent_id => 2, :position => 2},
1559
- {:id => 6, :name => "two.two.one", :parent_id => 5, :position => 1},
1560
- {:id => 7, :name => "one.two", :parent_id => 1, :position => 2},
1561
- {:id => 8, :name => "one.one", :parent_id => 1, :position => 1},
1562
- {:id => 9, :name => "five", :parent_id => nil, :position => 5},
1563
- {:id => 10, :name => "four", :parent_id => nil, :position => 4},
1564
- {:id => 11, :name => "five.one", :parent_id => 9, :position => 1},
1565
- {:id => 12, :name => "two.three", :parent_id => 2, :position => 3}]
1566
- @nodes.each{|node| @db[:nodes].insert(node)}
1567
-
1568
- class ::Node < Sequel::Model
1569
- plugin :tree
1570
- end
1571
- end
1572
- after(:all) do
1573
- @db.drop_table?(:nodes)
1574
- Object.send(:remove_const, :Node)
1575
- end
1576
-
1578
+ shared_examples_for "tree plugin" do
1577
1579
  it "should instantiate" do
1578
- Node.all.size.should == 12
1579
- end
1580
-
1581
- it "should find top level nodes" do
1582
- Node.roots_dataset.count.should == 5
1580
+ @Node.all.size.should == 12
1583
1581
  end
1584
1582
 
1585
1583
  it "should find all descendants of a node" do
1586
- two = Node.find(:id => 2)
1587
- two.name.should == "two"
1588
- two.descendants.map{|m| m[:id]}.should == [4, 5, 12, 6]
1584
+ @Node.find(:name => 'two').descendants.map{|m| m.name}.should == %w'two.one two.two two.three two.two.one'
1589
1585
  end
1590
1586
 
1591
1587
  it "should find all ancestors of a node" do
1592
- twotwoone = Node.find(:id => 6)
1593
- twotwoone.name.should == "two.two.one"
1594
- twotwoone.ancestors.map{|m| m[:id]}.should == [5, 2]
1588
+ @Node.find(:name => "two.two.one").ancestors.map{|m| m.name}.should == %w'two.two two'
1595
1589
  end
1596
1590
 
1597
1591
  it "should find all siblings of a node, excepting self" do
1598
- twoone = Node.find(:id => 4)
1599
- twoone.name.should == "two.one"
1600
- twoone.siblings.map{|m| m[:id]}.should == [5, 12]
1592
+ @Node.find(:name=>"two.one").siblings.map{|m| m.name}.should == %w'two.two two.three'
1601
1593
  end
1602
1594
 
1603
1595
  it "should find all siblings of a node, including self" do
1604
- twoone = Node.find(:id => 4)
1605
- twoone.name.should == "two.one"
1606
- twoone.self_and_siblings.map{|m| m[:id]}.should == [4, 5, 12]
1596
+ @Node.find(:name=>"two.one").self_and_siblings.map{|m| m.name}.should == %w'two.one two.two two.three'
1607
1597
  end
1608
1598
 
1609
1599
  it "should find siblings for root nodes" do
1610
- three = Node.find(:id => 3)
1611
- three.name.should == "three"
1612
- three.self_and_siblings.map{|m| m[:id]}.should == [1, 2, 3, 9, 10]
1600
+ @Node.find(:name=>'three').self_and_siblings.map{|m| m.name}.should == %w'one two three four five'
1613
1601
  end
1614
1602
 
1615
1603
  it "should find correct root for a node" do
1616
- twotwoone = Node.find(:id => 6)
1617
- twotwoone.name.should == "two.two.one"
1618
- twotwoone.root[:id].should == 2
1619
-
1620
- three = Node.find(:id => 3)
1621
- three.name.should == "three"
1622
- three.root[:id].should == 3
1623
-
1624
- fiveone = Node.find(:id => 11)
1625
- fiveone.name.should == "five.one"
1626
- fiveone.root[:id].should == 9
1604
+ @Node.find(:name=>"two.two.one").root.name.should == 'two'
1605
+ @Node.find(:name=>"three").root.name.should == 'three'
1606
+ @Node.find(:name=>"five.one").root.name.should == 'five'
1627
1607
  end
1628
1608
 
1629
- it "iterate top-level nodes in natural database order" do
1630
- Node.roots_dataset.count.should == 5
1631
- Node.roots.inject([]){|ids, p| ids << p.position}.should == [1, 2, 3, 5, 4]
1609
+ it "iterate top-level nodes in order" do
1610
+ @Node.roots_dataset.count.should == 5
1611
+ @Node.roots.map{|p| p.name}.should == %w'one two three four five'
1632
1612
  end
1633
1613
 
1634
1614
  it "should have children" do
1635
- one = Node.find(:id => 1)
1636
- one.name.should == "one"
1637
- one.children.size.should == 2
1638
- end
1639
-
1640
- it "children should be natural database order" do
1641
- one = Node.find(:id => 1)
1642
- one.name.should == "one"
1643
- one.children.map{|m| m[:position]}.should == [2, 1]
1615
+ @Node.find(:name=>'one').children.map{|m| m.name}.should == %w'one.one one.two'
1644
1616
  end
1617
+ end
1645
1618
 
1646
- describe "Nodes in specified order" do
1647
- before(:all) do
1648
- class ::OrderedNode < Sequel::Model(:nodes)
1649
- plugin :tree, :order => :position
1650
- end
1651
- end
1652
- after(:all) do
1653
- Object.send(:remove_const, :OrderedNode)
1619
+ describe "with simple key" do
1620
+ before(:all) do
1621
+ @db = DB
1622
+ @db.create_table!(:nodes) do
1623
+ Integer :id, :primary_key=>true
1624
+ String :name
1625
+ Integer :parent_id
1626
+ Integer :position
1654
1627
  end
1655
1628
 
1656
- it "iterate top-level nodes in order by position" do
1657
- OrderedNode.roots_dataset.count.should == 5
1658
- OrderedNode.roots.inject([]){|ids, p| ids << p.position}.should == [1, 2, 3, 4, 5]
1659
- end
1629
+ @nodes = [{:id => 1, :name => 'one', :parent_id => nil, :position => 1},
1630
+ {:id => 2, :name => 'two', :parent_id => nil, :position => 2},
1631
+ {:id => 3, :name => 'three', :parent_id => nil, :position => 3},
1632
+ {:id => 4, :name => "two.one", :parent_id => 2, :position => 1},
1633
+ {:id => 5, :name => "two.two", :parent_id => 2, :position => 2},
1634
+ {:id => 6, :name => "two.two.one", :parent_id => 5, :position => 1},
1635
+ {:id => 7, :name => "one.two", :parent_id => 1, :position => 2},
1636
+ {:id => 8, :name => "one.one", :parent_id => 1, :position => 1},
1637
+ {:id => 9, :name => "five", :parent_id => nil, :position => 5},
1638
+ {:id => 10, :name => "four", :parent_id => nil, :position => 4},
1639
+ {:id => 11, :name => "five.one", :parent_id => 9, :position => 1},
1640
+ {:id => 12, :name => "two.three", :parent_id => 2, :position => 3}]
1641
+ @nodes.each{|node| @db[:nodes].insert(node)}
1660
1642
 
1661
- it "children should be in specified order" do
1662
- one = OrderedNode.find(:id => 1)
1663
- one.name.should == "one"
1664
- one.children.map{|m| m[:position]}.should == [1, 2]
1665
- end
1643
+ @Node = Class.new(Sequel::Model(:nodes))
1644
+ @Node.plugin :tree, :order=>:position
1645
+ end
1646
+ after(:all) do
1647
+ @db.drop_table?(:nodes)
1666
1648
  end
1649
+
1650
+ it_should_behave_like "tree plugin"
1667
1651
  end
1668
1652
 
1669
- describe "Lorems in specified order" do
1653
+ describe "with composite key" do
1670
1654
  before(:all) do
1671
- @db.create_table!(:lorems) do
1672
- Integer :id, :primary_key=>true
1655
+ @db = DB
1656
+ @db.create_table!(:nodes) do
1657
+ Integer :id
1658
+ Integer :id2
1673
1659
  String :name
1674
- Integer :ipsum_id
1675
- Integer :neque
1660
+ Integer :parent_id
1661
+ Integer :parent_id2
1662
+ Integer :position
1663
+ primary_key [:id, :id2]
1676
1664
  end
1677
1665
 
1678
- @lorems = [{:id => 1, :name => 'Lorem', :ipsum_id => nil, :neque => 4},
1679
- {:id => 2, :name => 'Ipsum', :ipsum_id => nil, :neque => 3},
1680
- {:id => 4, :name => "Neque", :ipsum_id => 2, :neque => 2},
1681
- {:id => 5, :name => "Porro", :ipsum_id => 2, :neque => 1}]
1682
- @lorems.each{|lorem| @db[:lorems].insert(lorem)}
1666
+ @nodes = [{:id => 1, :id2=> 1, :name => 'one', :parent_id => nil, :parent_id2 => nil, :position => 1},
1667
+ {:id => 2, :id2=> 1, :name => 'two', :parent_id => nil, :parent_id2 => nil, :position => 2},
1668
+ {:id => 1, :id2=> 2, :name => 'three', :parent_id => nil, :parent_id2 => nil, :position => 3},
1669
+ {:id => 2, :id2=> 2, :name => "two.one", :parent_id => 2, :parent_id2 => 1, :position => 1},
1670
+ {:id => 3, :id2=> 1, :name => "two.two", :parent_id => 2, :parent_id2 => 1, :position => 2},
1671
+ {:id => 3, :id2=> 2, :name => "two.two.one", :parent_id => 3, :parent_id2 => 1, :position => 1},
1672
+ {:id => 3, :id2=> 3, :name => "one.two", :parent_id => 1, :parent_id2 => 1, :position => 2},
1673
+ {:id => 1, :id2=> 3, :name => "one.one", :parent_id => 1, :parent_id2 => 1, :position => 1},
1674
+ {:id => 2, :id2=> 3, :name => "five", :parent_id => nil, :parent_id2 => nil, :position => 5},
1675
+ {:id => 4, :id2=> 1, :name => "four", :parent_id => nil, :parent_id2 => nil, :position => 4},
1676
+ {:id => 1, :id2=> 4, :name => "five.one", :parent_id => 2, :parent_id2 => 3, :position => 1},
1677
+ {:id => 2, :id2=> 4, :name => "two.three", :parent_id => 2, :parent_id2 => 1, :position => 3}]
1678
+ @nodes.each{|node| @db[:nodes].insert(node)}
1683
1679
 
1684
- class ::Lorem < Sequel::Model
1685
- plugin :tree, :key => :ipsum_id, :order => :neque
1686
- end
1680
+ @Node = Class.new(Sequel::Model(:nodes))
1681
+ @Node.plugin :tree, :order=>:position, :key=>[:parent_id, :parent_id2]
1687
1682
  end
1688
1683
  after(:all) do
1689
- @db.drop_table?(:lorems)
1690
- Object.send(:remove_const, :Lorem)
1691
- end
1692
-
1693
- it "iterate top-level nodes in order by position" do
1694
- Lorem.roots_dataset.count.should == 2
1695
- Lorem.roots.inject([]){|ids, p| ids << p.neque}.should == [3, 4]
1684
+ @db.drop_table?(:nodes)
1696
1685
  end
1697
1686
 
1698
- it "children should be specified order" do
1699
- one = Lorem.find(:id => 2)
1700
- one.children.map{|m| m[:neque]}.should == [1, 2]
1701
- end
1687
+ it_should_behave_like "tree plugin"
1702
1688
  end
1703
1689
  end
1704
1690