sequel 3.9.0 → 3.10.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.
- data/CHANGELOG +56 -0
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/doc/advanced_associations.rdoc +7 -10
- data/doc/release_notes/3.10.0.txt +286 -0
- data/lib/sequel/adapters/do/mysql.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +5 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +30 -0
- data/lib/sequel/adapters/shared/mssql.rb +23 -9
- data/lib/sequel/adapters/shared/mysql.rb +12 -1
- data/lib/sequel/adapters/shared/postgres.rb +7 -18
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +5 -0
- data/lib/sequel/connection_pool/single.rb +3 -3
- data/lib/sequel/database.rb +3 -2
- data/lib/sequel/dataset.rb +6 -5
- data/lib/sequel/dataset/convenience.rb +3 -3
- data/lib/sequel/dataset/query.rb +13 -0
- data/lib/sequel/dataset/sql.rb +31 -1
- data/lib/sequel/extensions/schema_dumper.rb +3 -3
- data/lib/sequel/model.rb +8 -6
- data/lib/sequel/model/associations.rb +144 -102
- data/lib/sequel/model/base.rb +21 -1
- data/lib/sequel/model/plugins.rb +3 -1
- data/lib/sequel/plugins/association_dependencies.rb +14 -7
- data/lib/sequel/plugins/caching.rb +4 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/identity_map.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +3 -2
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/typecast_on_load.rb +16 -5
- data/lib/sequel/sql.rb +18 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -0
- data/spec/adapters/mysql_spec.rb +4 -0
- data/spec/adapters/postgres_spec.rb +55 -5
- data/spec/core/database_spec.rb +5 -3
- data/spec/core/dataset_spec.rb +86 -15
- data/spec/core/expression_filters_spec.rb +23 -6
- data/spec/extensions/association_dependencies_spec.rb +24 -5
- data/spec/extensions/association_proxies_spec.rb +3 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/identity_map_spec.rb +16 -0
- data/spec/extensions/nested_attributes_spec.rb +44 -1
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +6 -0
- data/spec/extensions/spec_helper.rb +6 -0
- data/spec/extensions/typecast_on_load_spec.rb +9 -0
- data/spec/extensions/validation_helpers_spec.rb +5 -5
- data/spec/integration/dataset_test.rb +13 -9
- data/spec/integration/eager_loader_test.rb +56 -1
- data/spec/integration/model_test.rb +8 -0
- data/spec/integration/plugin_test.rb +270 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/model/associations_spec.rb +541 -118
- data/spec/model/eager_loading_spec.rb +24 -3
- data/spec/model/record_spec.rb +34 -0
- metadata +9 -2
@@ -82,6 +82,8 @@ describe "Sequel::Database dump methods" do
|
|
82
82
|
[[:c1, {:db_type=>'blahblah', :allow_null=>true}]]
|
83
83
|
when :t6
|
84
84
|
[[:c1, {:db_type=>'bigint', :primary_key=>true, :allow_null=>true}]]
|
85
|
+
when :t7
|
86
|
+
[[:c1, {:db_type=>'somedbspecifictype', :primary_key=>true, :allow_null=>false}]]
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
@@ -94,6 +96,10 @@ describe "Sequel::Database dump methods" do
|
|
94
96
|
@d.dump_table_schema(:t6).should == "create_table(:t6) do\n primary_key :c1, :type=>Bignum\nend"
|
95
97
|
end
|
96
98
|
|
99
|
+
it "should dump primary key columns with explicit :type equal to the database type when :same_db option is passed" do
|
100
|
+
@d.dump_table_schema(:t7, :same_db => true).should == "create_table(:t7) do\n primary_key :c1, :type=>\"somedbspecifictype\"\nend"
|
101
|
+
end
|
102
|
+
|
97
103
|
it "should use a composite primary_key calls if there is a composite primary key" do
|
98
104
|
@d.dump_table_schema(:t2).should == "create_table(:t2) do\n Integer :c1, :null=>false\n BigDecimal :c2, :null=>false\n \n primary_key [:c1, :c2]\nend"
|
99
105
|
end
|
@@ -7,6 +7,7 @@ describe Sequel::Model, "TypecastOnLoad plugin" do
|
|
7
7
|
[[:id, {}], [:y, {:type=>:boolean, :db_type=>'tinyint(1)'}], [:b, {:type=>:integer, :db_type=>'integer'}]]
|
8
8
|
end
|
9
9
|
@c = Class.new(Sequel::Model(@db[:items])) do
|
10
|
+
include(Module.new{def _refresh(ds); values[:b] = b.to_s; self; end})
|
10
11
|
attr_accessor :bset
|
11
12
|
def b=(x)
|
12
13
|
self.bset = true
|
@@ -26,6 +27,14 @@ describe Sequel::Model, "TypecastOnLoad plugin" do
|
|
26
27
|
o.bset.should == true
|
27
28
|
end
|
28
29
|
|
30
|
+
specify "should call setter method with value when reloading the object, for all given columns" do
|
31
|
+
@c.plugin :typecast_on_load, :b
|
32
|
+
o = @c.new({:id=>1, :b=>"1", :y=>"0"}, true)
|
33
|
+
o.refresh
|
34
|
+
o.values.should == {:id=>1, :b=>1, :y=>"0"}
|
35
|
+
o.bset.should == true
|
36
|
+
end
|
37
|
+
|
29
38
|
specify "should allowing setting columns separately via add_typecast_on_load_columns" do
|
30
39
|
@c.plugin :typecast_on_load
|
31
40
|
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}
|
@@ -377,7 +377,7 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
377
377
|
|
378
378
|
@user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
|
379
379
|
@user.should be_valid
|
380
|
-
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((
|
380
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest') AND (id != 1)) LIMIT 1"
|
381
381
|
@user = @c.new(:username => "0records", :password => "anothertest")
|
382
382
|
@user.should be_valid
|
383
383
|
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
|
@@ -398,7 +398,7 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
398
398
|
@c.new(:username => "0records", :password => "anothertest").should be_valid
|
399
399
|
@c.load(:id=>3, :username => "0records", :password => "anothertest").should be_valid
|
400
400
|
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active) LIMIT 1",
|
401
|
-
"SELECT COUNT(*) AS count FROM items WHERE ((
|
401
|
+
"SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active AND (id != 3)) LIMIT 1"]
|
402
402
|
end
|
403
403
|
|
404
404
|
it "should support :only_if_modified option for validates_unique, and not check uniqueness for existing records if values haven't changed" do
|
@@ -423,16 +423,16 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
423
423
|
|
424
424
|
m.username = '1'
|
425
425
|
m.should be_valid
|
426
|
-
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((
|
426
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '1') AND (password = 'anothertest') AND (id != 3)) LIMIT 1"]
|
427
427
|
|
428
428
|
m = @c.load(:id=>3, :username => "0records", :password => "anothertest")
|
429
429
|
MODEL_DB.reset
|
430
430
|
m.password = '1'
|
431
431
|
m.should be_valid
|
432
|
-
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((
|
432
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = '1') AND (id != 3)) LIMIT 1"]
|
433
433
|
MODEL_DB.reset
|
434
434
|
m.username = '2'
|
435
435
|
m.should be_valid
|
436
|
-
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((
|
436
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '2') AND (password = '1') AND (id != 3)) LIMIT 1"]
|
437
437
|
end
|
438
438
|
end
|
@@ -266,6 +266,10 @@ describe "Simple Dataset operations in transactions" do
|
|
266
266
|
@ds.order(:id).all.should == [{:id=>1, :number=>20}]
|
267
267
|
end
|
268
268
|
end
|
269
|
+
|
270
|
+
specify "should support for_update" do
|
271
|
+
INTEGRATION_DB.transaction{@ds.for_update.all.should == []}
|
272
|
+
end
|
269
273
|
end
|
270
274
|
|
271
275
|
describe "Dataset UNION, EXCEPT, and INTERSECT" do
|
@@ -536,23 +540,23 @@ describe "Sequel::Dataset convenience methods" do
|
|
536
540
|
end
|
537
541
|
|
538
542
|
it "#group_and_count should return a grouping by count" do
|
539
|
-
@ds.group_and_count(:a).all.should == []
|
543
|
+
@ds.group_and_count(:a).order(:count).all.should == []
|
540
544
|
@ds.insert(20, 10)
|
541
|
-
@ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>1}]
|
545
|
+
@ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>1}]
|
542
546
|
@ds.insert(20, 30)
|
543
|
-
@ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>2}]
|
547
|
+
@ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>2}]
|
544
548
|
@ds.insert(30, 30)
|
545
|
-
@ds.group_and_count(:a).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
|
549
|
+
@ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
|
546
550
|
end
|
547
551
|
|
548
552
|
it "#group_and_count should support column aliases" do
|
549
|
-
@ds.group_and_count(:a___c).all.should == []
|
553
|
+
@ds.group_and_count(:a___c).order(:count).all.should == []
|
550
554
|
@ds.insert(20, 10)
|
551
|
-
@ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>1}]
|
555
|
+
@ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>1}]
|
552
556
|
@ds.insert(20, 30)
|
553
|
-
@ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>2}]
|
557
|
+
@ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>2}]
|
554
558
|
@ds.insert(30, 30)
|
555
|
-
@ds.group_and_count(:a___c).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
|
559
|
+
@ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
|
556
560
|
end
|
557
561
|
|
558
562
|
cspecify "#range should return the range between the maximum and minimum values", :sqlite do
|
@@ -596,7 +600,7 @@ describe "Sequel::Dataset main SQL methods" do
|
|
596
600
|
@ds.filter("b < ?", 15).invert.all.should == [{:a=>20, :b=>30}]
|
597
601
|
end
|
598
602
|
|
599
|
-
it "#and and #or should work
|
603
|
+
it "#and and #or should work correctly" do
|
600
604
|
@ds.insert(20, 30)
|
601
605
|
@ds.filter(:a=>20).and(:b=>30).all.should == [{:a=>20, :b=>30}]
|
602
606
|
@ds.filter(:a=>20).and(:b=>15).all.should == []
|
@@ -624,7 +624,7 @@ describe "statistics associations" do
|
|
624
624
|
String :name
|
625
625
|
end
|
626
626
|
class ::Project < Sequel::Model
|
627
|
-
many_to_one :ticket_hours, :read_only=>true, :key=>:id,
|
627
|
+
many_to_one :ticket_hours, :read_only=>true, :key=>:id, :class=>:Ticket,
|
628
628
|
:dataset=>proc{Ticket.filter(:project_id=>id).select{sum(hours).as(hours)}},
|
629
629
|
:eager_loader=>(proc do |kh, projects, a|
|
630
630
|
projects.each{|p| p.associations[:ticket_hours] = nil}
|
@@ -677,3 +677,58 @@ describe "statistics associations" do
|
|
677
677
|
p2.ticket_hours.to_i.should == 22
|
678
678
|
end
|
679
679
|
end
|
680
|
+
|
681
|
+
describe "one to one associations" do
|
682
|
+
before do
|
683
|
+
INTEGRATION_DB.create_table!(:books) do
|
684
|
+
primary_key :id
|
685
|
+
end
|
686
|
+
class ::Book < Sequel::Model
|
687
|
+
one_to_one :first_page, :class=>:Page, :conditions=>{:page_number=>1}
|
688
|
+
one_to_one :second_page, :class=>:Page, :conditions=>{:page_number=>2}
|
689
|
+
end
|
690
|
+
|
691
|
+
INTEGRATION_DB.create_table!(:pages) do
|
692
|
+
primary_key :id
|
693
|
+
foreign_key :book_id, :books
|
694
|
+
Integer :page_number
|
695
|
+
end
|
696
|
+
class ::Page < Sequel::Model
|
697
|
+
many_to_one :book
|
698
|
+
end
|
699
|
+
|
700
|
+
@book1 = Book.create
|
701
|
+
@book2 = Book.create
|
702
|
+
@page1 = Page.create(:book=>@book1, :page_number=>1)
|
703
|
+
@page2 = Page.create(:book=>@book1, :page_number=>2)
|
704
|
+
@page3 = Page.create(:book=>@book2, :page_number=>1)
|
705
|
+
@page4 = Page.create(:book=>@book2, :page_number=>2)
|
706
|
+
clear_sqls
|
707
|
+
end
|
708
|
+
|
709
|
+
after do
|
710
|
+
INTEGRATION_DB.drop_table :pages, :books
|
711
|
+
Object.send(:remove_const, :Book)
|
712
|
+
Object.send(:remove_const, :Page)
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should be eager loadable" do
|
716
|
+
bk1, bk2 = Book.filter(:books__id=>[1,2]).eager(:first_page).all
|
717
|
+
bk1.first_page.should == @page1
|
718
|
+
bk2.first_page.should == @page3
|
719
|
+
end
|
720
|
+
|
721
|
+
it "should be eager graphable" do
|
722
|
+
bk1, bk2 = Book.filter(:books__id=>[1,2]).eager_graph(:first_page).all
|
723
|
+
bk1.first_page.should == @page1
|
724
|
+
bk2.first_page.should == @page3
|
725
|
+
end
|
726
|
+
|
727
|
+
it "should be eager graphable two at once" do
|
728
|
+
bk1, bk2 = Book.filter(:books__id=>[1,2]).eager_graph(:first_page, :second_page).all
|
729
|
+
bk1.first_page.should == @page1
|
730
|
+
bk1.second_page.should == @page2
|
731
|
+
bk2.first_page.should == @page3
|
732
|
+
bk2.second_page.should == @page4
|
733
|
+
end
|
734
|
+
end
|
@@ -107,4 +107,12 @@ describe "Sequel::Model basic support" do
|
|
107
107
|
proc{i2 = Marshal.load(s)}.should_not raise_error
|
108
108
|
i2.should == i
|
109
109
|
end
|
110
|
+
|
111
|
+
specify "#lock! should lock records" do
|
112
|
+
Item.db.transaction do
|
113
|
+
i = Item.create(:name=>'J')
|
114
|
+
i.lock!
|
115
|
+
i.update(:name=>'K')
|
116
|
+
end
|
117
|
+
end
|
110
118
|
end
|
@@ -482,3 +482,273 @@ describe "OptimisticLocking plugin" do
|
|
482
482
|
proc{p1.update(:name=>'Bob')}.should_not raise_error
|
483
483
|
end
|
484
484
|
end
|
485
|
+
|
486
|
+
describe "Composition plugin" do
|
487
|
+
before do
|
488
|
+
@db = INTEGRATION_DB
|
489
|
+
@db.create_table!(:events) do
|
490
|
+
primary_key :id
|
491
|
+
Integer :year
|
492
|
+
Integer :month
|
493
|
+
Integer :day
|
494
|
+
end
|
495
|
+
class ::Event < Sequel::Model(@db)
|
496
|
+
plugin :composition
|
497
|
+
composition :date, :composer=>proc{Date.new(year, month, day) if year && month && day}, :decomposer=>(proc do
|
498
|
+
if date
|
499
|
+
self.year = date.year
|
500
|
+
self.month = date.month
|
501
|
+
self.day = date.day
|
502
|
+
else
|
503
|
+
self.year, self.month, self.day = nil
|
504
|
+
end
|
505
|
+
end)
|
506
|
+
composition :date, :mapping=>[:year, :month, :day]
|
507
|
+
end
|
508
|
+
@e1 = Event.create(:year=>2010, :month=>2, :day=>15)
|
509
|
+
@e2 = Event.create({})
|
510
|
+
end
|
511
|
+
after do
|
512
|
+
@db.drop_table(:events)
|
513
|
+
Object.send(:remove_const, :Event)
|
514
|
+
end
|
515
|
+
|
516
|
+
specify "should return a composed object if the underlying columns have a value" do
|
517
|
+
@e1.date.should == Date.civil(2010, 2, 15)
|
518
|
+
@e2.date.should == nil
|
519
|
+
end
|
520
|
+
|
521
|
+
specify "should decompose the object when saving the record" do
|
522
|
+
@e1.date = Date.civil(2009, 1, 2)
|
523
|
+
@e1.save
|
524
|
+
@e1.year.should == 2009
|
525
|
+
@e1.month.should == 1
|
526
|
+
@e1.day.should == 2
|
527
|
+
end
|
528
|
+
|
529
|
+
specify "should save all columns when saving changes" do
|
530
|
+
@e2.date = Date.civil(2009, 10, 2)
|
531
|
+
@e2.save_changes
|
532
|
+
@e2.reload
|
533
|
+
@e2.year.should == 2009
|
534
|
+
@e2.month.should == 10
|
535
|
+
@e2.day.should == 2
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
if INTEGRATION_DB.dataset.supports_cte?
|
540
|
+
describe "RcteTree Plugin" do
|
541
|
+
before do
|
542
|
+
@db = INTEGRATION_DB
|
543
|
+
@db.create_table!(:nodes) do
|
544
|
+
primary_key :id
|
545
|
+
Integer :parent_id
|
546
|
+
String :name
|
547
|
+
end
|
548
|
+
class ::Node < Sequel::Model(@db)
|
549
|
+
plugin :rcte_tree, :order=>:name
|
550
|
+
end
|
551
|
+
|
552
|
+
@a = Node.create(:name=>'a')
|
553
|
+
@b = Node.create(:name=>'b')
|
554
|
+
@aa = Node.create(:name=>'aa', :parent=>@a)
|
555
|
+
@ab = Node.create(:name=>'ab', :parent=>@a)
|
556
|
+
@ba = Node.create(:name=>'ba', :parent=>@b)
|
557
|
+
@bb = Node.create(:name=>'bb', :parent=>@b)
|
558
|
+
@aaa = Node.create(:name=>'aaa', :parent=>@aa)
|
559
|
+
@aab = Node.create(:name=>'aab', :parent=>@aa)
|
560
|
+
@aba = Node.create(:name=>'aba', :parent=>@ab)
|
561
|
+
@abb = Node.create(:name=>'abb', :parent=>@ab)
|
562
|
+
@aaaa = Node.create(:name=>'aaaa', :parent=>@aaa)
|
563
|
+
@aaab = Node.create(:name=>'aaab', :parent=>@aaa)
|
564
|
+
@aaaaa = Node.create(:name=>'aaaaa', :parent=>@aaaa)
|
565
|
+
end
|
566
|
+
after do
|
567
|
+
@db.drop_table :nodes
|
568
|
+
Object.send(:remove_const, :Node)
|
569
|
+
end
|
570
|
+
|
571
|
+
specify "should load all standard (not-CTE) methods correctly" do
|
572
|
+
@a.children.should == [@aa, @ab]
|
573
|
+
@b.children.should == [@ba, @bb]
|
574
|
+
@aa.children.should == [@aaa, @aab]
|
575
|
+
@ab.children.should == [@aba, @abb]
|
576
|
+
@ba.children.should == []
|
577
|
+
@bb.children.should == []
|
578
|
+
@aaa.children.should == [@aaaa, @aaab]
|
579
|
+
@aab.children.should == []
|
580
|
+
@aba.children.should == []
|
581
|
+
@abb.children.should == []
|
582
|
+
@aaaa.children.should == [@aaaaa]
|
583
|
+
@aaab.children.should == []
|
584
|
+
@aaaaa.children.should == []
|
585
|
+
|
586
|
+
@a.parent.should == nil
|
587
|
+
@b.parent.should == nil
|
588
|
+
@aa.parent.should == @a
|
589
|
+
@ab.parent.should == @a
|
590
|
+
@ba.parent.should == @b
|
591
|
+
@bb.parent.should == @b
|
592
|
+
@aaa.parent.should == @aa
|
593
|
+
@aab.parent.should == @aa
|
594
|
+
@aba.parent.should == @ab
|
595
|
+
@abb.parent.should == @ab
|
596
|
+
@aaaa.parent.should == @aaa
|
597
|
+
@aaab.parent.should == @aaa
|
598
|
+
@aaaaa.parent.should == @aaaa
|
599
|
+
end
|
600
|
+
|
601
|
+
specify "should load all ancestors and descendants lazily for a given instance" do
|
602
|
+
@a.descendants.should == [@aa, @aaa, @aaaa, @aaaaa, @aaab, @aab, @ab, @aba, @abb]
|
603
|
+
@b.descendants.should == [@ba, @bb]
|
604
|
+
@aa.descendants.should == [@aaa, @aaaa, @aaaaa, @aaab, @aab]
|
605
|
+
@ab.descendants.should == [@aba, @abb]
|
606
|
+
@ba.descendants.should == []
|
607
|
+
@bb.descendants.should == []
|
608
|
+
@aaa.descendants.should == [@aaaa, @aaaaa, @aaab]
|
609
|
+
@aab.descendants.should == []
|
610
|
+
@aba.descendants.should == []
|
611
|
+
@abb.descendants.should == []
|
612
|
+
@aaaa.descendants.should == [@aaaaa]
|
613
|
+
@aaab.descendants.should == []
|
614
|
+
@aaaaa.descendants.should == []
|
615
|
+
|
616
|
+
@a.ancestors.should == []
|
617
|
+
@b.ancestors.should == []
|
618
|
+
@aa.ancestors.should == [@a]
|
619
|
+
@ab.ancestors.should == [@a]
|
620
|
+
@ba.ancestors.should == [@b]
|
621
|
+
@bb.ancestors.should == [@b]
|
622
|
+
@aaa.ancestors.should == [@a, @aa]
|
623
|
+
@aab.ancestors.should == [@a, @aa]
|
624
|
+
@aba.ancestors.should == [@a, @ab]
|
625
|
+
@abb.ancestors.should == [@a, @ab]
|
626
|
+
@aaaa.ancestors.should == [@a, @aa, @aaa]
|
627
|
+
@aaab.ancestors.should == [@a, @aa, @aaa]
|
628
|
+
@aaaaa.ancestors.should == [@a, @aa, @aaa, @aaaa]
|
629
|
+
end
|
630
|
+
|
631
|
+
specify "should eagerly load all ancestors and descendants for a dataset" do
|
632
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
|
633
|
+
nodes.should == [@a, @aaa, @b]
|
634
|
+
nodes[0].descendants.should == [@aa, @aaa, @aaaa, @aaaaa, @aaab, @aab, @ab, @aba, @abb]
|
635
|
+
nodes[1].descendants.should == [@aaaa, @aaaaa, @aaab]
|
636
|
+
nodes[2].descendants.should == [@ba, @bb]
|
637
|
+
nodes[0].ancestors.should == []
|
638
|
+
nodes[1].ancestors.should == [@a, @aa]
|
639
|
+
nodes[2].ancestors.should == []
|
640
|
+
end
|
641
|
+
|
642
|
+
specify "should eagerly load descendants to a given level" do
|
643
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>1).all
|
644
|
+
nodes.should == [@a, @aaa, @b]
|
645
|
+
nodes[0].descendants.should == [@aa, @ab]
|
646
|
+
nodes[1].descendants.should == [@aaaa, @aaab]
|
647
|
+
nodes[2].descendants.should == [@ba, @bb]
|
648
|
+
|
649
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>2).all
|
650
|
+
nodes.should == [@a, @aaa, @b]
|
651
|
+
nodes[0].descendants.should == [@aa, @aaa, @aab, @ab, @aba, @abb]
|
652
|
+
nodes[1].descendants.should == [@aaaa, @aaaaa, @aaab]
|
653
|
+
nodes[2].descendants.should == [@ba, @bb]
|
654
|
+
end
|
655
|
+
|
656
|
+
specify "should populate all :children associations when eagerly loading descendants for a dataset" do
|
657
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants).all
|
658
|
+
nodes[0].associations[:children].should == [@aa, @ab]
|
659
|
+
nodes[1].associations[:children].should == [@aaaa, @aaab]
|
660
|
+
nodes[2].associations[:children].should == [@ba, @bb]
|
661
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaa, @aab], [@aba, @abb]]
|
662
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaaaa], []]
|
663
|
+
nodes[2].associations[:children].map{|c1| c1.associations[:children]}.should == [[], []]
|
664
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@aaaa, @aaab], []], [[], []]]
|
665
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[]], []]
|
666
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children]}}}.should == [[[[@aaaaa], []], []], [[], []]]
|
667
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children].map{|c4| c4.associations[:children]}}}}.should == [[[[[]], []], []], [[], []]]
|
668
|
+
end
|
669
|
+
|
670
|
+
specify "should not populate :children associations for final level when loading descendants to a given level" do
|
671
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>1).all
|
672
|
+
nodes[0].associations[:children].should == [@aa, @ab]
|
673
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children]}.should == [nil, nil]
|
674
|
+
nodes[1].associations[:children].should == [@aaaa, @aaab]
|
675
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children]}.should == [nil, nil]
|
676
|
+
nodes[2].associations[:children].should == [@ba, @bb]
|
677
|
+
nodes[2].associations[:children].map{|c1| c1.associations[:children]}.should == [nil, nil]
|
678
|
+
|
679
|
+
nodes[0].associations[:children].map{|c1| c1.children}.should == [[@aaa, @aab], [@aba, @abb]]
|
680
|
+
nodes[1].associations[:children].map{|c1| c1.children}.should == [[@aaaaa], []]
|
681
|
+
nodes[2].associations[:children].map{|c1| c1.children}.should == [[], []]
|
682
|
+
|
683
|
+
nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:descendants=>2).all
|
684
|
+
nodes[0].associations[:children].should == [@aa, @ab]
|
685
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaa, @aab], [@aba, @abb]]
|
686
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@aaaa, @aaab], nil], [nil, nil]]
|
687
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| (cc2 = c2.associations[:children]) ? cc2.map{|c3| c3.associations[:children]} : nil}}.should == [[[[@aaaaa], []], nil], [nil, nil]]
|
688
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| (cc2 = c2.associations[:children]) ? cc2.map{|c3| (cc3 = c3.associations[:children]) ? cc3.map{|c4| c4.associations[:children]} : nil} : nil}}.should == [[[[nil], []], nil], [nil, nil]]
|
689
|
+
|
690
|
+
nodes[1].associations[:children].should == [@aaaa, @aaab]
|
691
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaaaa], []]
|
692
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[nil], []]
|
693
|
+
|
694
|
+
nodes[2].associations[:children].should == [@ba, @bb]
|
695
|
+
nodes[2].associations[:children].map{|c1| c1.associations[:children]}.should == [[], []]
|
696
|
+
|
697
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.children}}.should == [[[@aaaa, @aaab], []], [[], []]]
|
698
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.children.map{|c3| c3.children}}}.should == [[[[@aaaaa], []], []], [[], []]]
|
699
|
+
nodes[0].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.children.map{|c3| c3.children.map{|c4| c4.children}}}}.should == [[[[[]], []], []], [[], []]]
|
700
|
+
nodes[1].associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.children}}.should == [[[]], []]
|
701
|
+
end
|
702
|
+
|
703
|
+
specify "should populate all :children associations when lazily loading descendants" do
|
704
|
+
@a.descendants
|
705
|
+
@a.associations[:children].should == [@aa, @ab]
|
706
|
+
@a.associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaa, @aab], [@aba, @abb]]
|
707
|
+
@a.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@aaaa, @aaab], []], [[], []]]
|
708
|
+
@a.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children]}}}.should == [[[[@aaaaa], []], []], [[], []]]
|
709
|
+
@a.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children].map{|c4| c4.associations[:children]}}}}.should == [[[[[]], []], []], [[], []]]
|
710
|
+
|
711
|
+
@b.descendants
|
712
|
+
@b.associations[:children].should == [@ba, @bb]
|
713
|
+
@b.associations[:children].map{|c1| c1.associations[:children]}.should == [[], []]
|
714
|
+
|
715
|
+
@aaa.descendants
|
716
|
+
@aaa.associations[:children].map{|c1| c1.associations[:children]}.should == [[@aaaaa], []]
|
717
|
+
@aaa.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[]], []]
|
718
|
+
end
|
719
|
+
|
720
|
+
specify "should populate all :parent associations when eagerly loading ancestors for a dataset" do
|
721
|
+
nodes = Node.filter(:id=>[@a.id, @ba.id, @aaa.id, @aaaaa.id]).order(:name).eager(:ancestors).all
|
722
|
+
nodes[0].associations.fetch(:parent, 1).should == nil
|
723
|
+
nodes[1].associations[:parent].should == @aa
|
724
|
+
nodes[1].associations[:parent].associations[:parent].should == @a
|
725
|
+
nodes[1].associations[:parent].associations[:parent].associations.fetch(:parent, 1) == nil
|
726
|
+
nodes[2].associations[:parent].should == @aaaa
|
727
|
+
nodes[2].associations[:parent].associations[:parent].should == @aaa
|
728
|
+
nodes[2].associations[:parent].associations[:parent].associations[:parent].should == @aa
|
729
|
+
nodes[2].associations[:parent].associations[:parent].associations[:parent].associations[:parent].should == @a
|
730
|
+
nodes[2].associations[:parent].associations[:parent].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
|
731
|
+
nodes[3].associations[:parent].should == @b
|
732
|
+
nodes[3].associations[:parent].associations.fetch(:parent, 1).should == nil
|
733
|
+
end
|
734
|
+
|
735
|
+
specify "should populate all :parent associations when lazily loading ancestors" do
|
736
|
+
@a.reload
|
737
|
+
@a.ancestors
|
738
|
+
@a.associations[:parent].should == nil
|
739
|
+
|
740
|
+
@ba.reload
|
741
|
+
@ba.ancestors
|
742
|
+
@ba.associations[:parent].should == @b
|
743
|
+
@ba.associations[:parent].associations.fetch(:parent, 1).should == nil
|
744
|
+
|
745
|
+
@ba.reload
|
746
|
+
@aaaaa.ancestors
|
747
|
+
@aaaaa.associations[:parent].should == @aaaa
|
748
|
+
@aaaaa.associations[:parent].associations[:parent].should == @aaa
|
749
|
+
@aaaaa.associations[:parent].associations[:parent].associations[:parent].should == @aa
|
750
|
+
@aaaaa.associations[:parent].associations[:parent].associations[:parent].associations[:parent].should == @a
|
751
|
+
@aaaaa.associations[:parent].associations[:parent].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
|
752
|
+
end
|
753
|
+
end
|
754
|
+
end
|