sequel 3.9.0 → 3.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -43,5 +43,8 @@ describe "Sequel::Plugins::AssociationProxies" do
|
|
43
43
|
it "should not return a proxy object for associations that do not return an array" do
|
44
44
|
Item.many_to_one :tag
|
45
45
|
proc{@i.tag.filter(:a=>1)}.should raise_error(NoMethodError)
|
46
|
+
|
47
|
+
Tag.one_to_one :item
|
48
|
+
proc{Tag.load(:id=>1, :item_id=>2).item.filter(:a=>1)}.should raise_error(NoMethodError)
|
46
49
|
end
|
47
50
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
describe "Serialization plugin" do
|
7
|
+
before do
|
8
|
+
@c = Class.new(Sequel::Model(:items))
|
9
|
+
@c.plugin :composition
|
10
|
+
@c.columns :id, :year, :month, :day
|
11
|
+
@o = @c.load(:id=>1, :year=>1, :month=>2, :day=>3)
|
12
|
+
MODEL_DB.reset
|
13
|
+
end
|
14
|
+
|
15
|
+
it ".composition should add compositions" do
|
16
|
+
@o.should_not respond_to(:date)
|
17
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
18
|
+
@o.date.should == Date.new(1, 2, 3)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "loading the plugin twice should not remove existing compositions" do
|
22
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
23
|
+
@c.plugin :composition
|
24
|
+
@c.compositions.keys.should == [:date]
|
25
|
+
end
|
26
|
+
|
27
|
+
it ".composition should raise an error if :composer and :decomposer options are not present and :mapping option is not provided" do
|
28
|
+
proc{@c.composition :date}.should raise_error(Sequel::Error)
|
29
|
+
proc{@c.composition :date, :composer=>proc{}, :decomposer=>proc{}}.should_not raise_error
|
30
|
+
proc{@c.composition :date, :mapping=>[]}.should_not raise_error
|
31
|
+
end
|
32
|
+
|
33
|
+
it ".compositions should return the reflection hash of compositions" do
|
34
|
+
@c.compositions.should == {}
|
35
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
36
|
+
@c.compositions.keys.should == [:date]
|
37
|
+
r = @c.compositions.values.first
|
38
|
+
r[:mapping].should == [:year, :month, :day]
|
39
|
+
r[:composer].should be_a_kind_of(Proc)
|
40
|
+
r[:decomposer].should be_a_kind_of(Proc)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "#compositions should be a hash of cached values of compositions" do
|
44
|
+
@o.compositions.should == {}
|
45
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
46
|
+
@o.date
|
47
|
+
@o.compositions.should == {:date=>Date.new(1, 2, 3)}
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should work with custom :composer and :decomposer options" do
|
51
|
+
@c.composition :date, :composer=>proc{Date.new(year+1, month+2, day+3)}, :decomposer=>proc{[:year, :month, :day].each{|s| self.send("#{s}=", date.send(s) * 2)}}
|
52
|
+
@o.date.should == Date.new(2, 4, 6)
|
53
|
+
@o.save
|
54
|
+
MODEL_DB.sqls.last.should include("year = 4")
|
55
|
+
MODEL_DB.sqls.last.should include("month = 8")
|
56
|
+
MODEL_DB.sqls.last.should include("day = 12")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should allow call super in composition getter and setter method definition in class" do
|
60
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
61
|
+
@c.class_eval do
|
62
|
+
def date
|
63
|
+
super + 1
|
64
|
+
end
|
65
|
+
def date=(v)
|
66
|
+
super(v - 3)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@o.date.should == Date.new(1, 2, 4)
|
70
|
+
@o.compositions[:date].should == Date.new(1, 2, 3)
|
71
|
+
@o.date = Date.new(1, 3, 5)
|
72
|
+
@o.compositions[:date].should == Date.new(1, 3, 2)
|
73
|
+
@o.date.should == Date.new(1, 3, 3)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should mark the object as modified whenever the composition is set" do
|
77
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
78
|
+
@o.modified?.should == false
|
79
|
+
@o.date = Date.new(3, 4, 5)
|
80
|
+
@o.modified?.should == true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should only decompose existing compositions" do
|
84
|
+
called = false
|
85
|
+
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
86
|
+
called.should == false
|
87
|
+
@o.save
|
88
|
+
called.should == false
|
89
|
+
@o.date = Date.new(1,2,3)
|
90
|
+
called.should == false
|
91
|
+
@o.save_changes
|
92
|
+
called.should == true
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should clear compositions cache when reloading" do
|
96
|
+
@c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
|
97
|
+
@o.date = Date.new(3, 4, 5)
|
98
|
+
@o.reload
|
99
|
+
@o.compositions.should == {}
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should instantiate compositions lazily" do
|
103
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
104
|
+
@o.compositions.should == {}
|
105
|
+
@o.date
|
106
|
+
@o.compositions.should == {:date=>Date.new(1,2,3)}
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should cache value of composition" do
|
110
|
+
times = 0
|
111
|
+
@c.composition :date, :composer=>proc{times+=1}, :decomposer=>proc{called = true}
|
112
|
+
times.should == 0
|
113
|
+
@o.date
|
114
|
+
times.should == 1
|
115
|
+
@o.date
|
116
|
+
times.should == 1
|
117
|
+
end
|
118
|
+
|
119
|
+
it ":class option should take an string, symbol, or class" do
|
120
|
+
@c.composition :date1, :class=>'Date', :mapping=>[:year, :month, :day]
|
121
|
+
@c.composition :date2, :class=>:Date, :mapping=>[:year, :month, :day]
|
122
|
+
@c.composition :date3, :class=>Date, :mapping=>[:year, :month, :day]
|
123
|
+
@o.date1.should == Date.new(1, 2, 3)
|
124
|
+
@o.date2.should == Date.new(1, 2, 3)
|
125
|
+
@o.date3.should == Date.new(1, 2, 3)
|
126
|
+
end
|
127
|
+
|
128
|
+
it ":mapping option should work with a single array of symbols" do
|
129
|
+
c = Class.new do
|
130
|
+
def initialize(y, m)
|
131
|
+
@y, @m = y, m
|
132
|
+
end
|
133
|
+
def year
|
134
|
+
@y * 2
|
135
|
+
end
|
136
|
+
def month
|
137
|
+
@m * 3
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@c.composition :date, :class=>c, :mapping=>[:year, :month]
|
141
|
+
@o.date.year.should == 2
|
142
|
+
@o.date.month.should == 6
|
143
|
+
@o.date = c.new(3, 4)
|
144
|
+
@o.save
|
145
|
+
MODEL_DB.sqls.last.should include("year = 6")
|
146
|
+
MODEL_DB.sqls.last.should include("month = 12")
|
147
|
+
end
|
148
|
+
|
149
|
+
it ":mapping option should work with an array of two pairs of symbols" do
|
150
|
+
c = Class.new do
|
151
|
+
def initialize(y, m)
|
152
|
+
@y, @m = y, m
|
153
|
+
end
|
154
|
+
def y
|
155
|
+
@y * 2
|
156
|
+
end
|
157
|
+
def m
|
158
|
+
@m * 3
|
159
|
+
end
|
160
|
+
end
|
161
|
+
@c.composition :date, :class=>c, :mapping=>[[:year, :y], [:month, :m]]
|
162
|
+
@o.date.y.should == 2
|
163
|
+
@o.date.m.should == 6
|
164
|
+
@o.date = c.new(3, 4)
|
165
|
+
@o.save
|
166
|
+
MODEL_DB.sqls.last.should include("year = 6")
|
167
|
+
MODEL_DB.sqls.last.should include("month = 12")
|
168
|
+
end
|
169
|
+
|
170
|
+
it ":mapping option :composer should return nil if all values are nil" do
|
171
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
172
|
+
@c.new.date.should == nil
|
173
|
+
end
|
174
|
+
|
175
|
+
it ":mapping option :decomposer should set all related fields to nil if nil" do
|
176
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
177
|
+
@o.date = nil
|
178
|
+
@o.save
|
179
|
+
MODEL_DB.sqls.last.should include("year = NULL")
|
180
|
+
MODEL_DB.sqls.last.should include("month = NULL")
|
181
|
+
MODEL_DB.sqls.last.should include("day = NULL")
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should work correctly with subclasses" do
|
185
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
186
|
+
c = Class.new(@c)
|
187
|
+
o = c.load(:id=>1, :year=>1, :month=>2, :day=>3)
|
188
|
+
o.date.should == Date.new(1, 2, 3)
|
189
|
+
o.save
|
190
|
+
MODEL_DB.sqls.last.should include("year = 1")
|
191
|
+
MODEL_DB.sqls.last.should include("month = 2")
|
192
|
+
MODEL_DB.sqls.last.should include("day = 3")
|
193
|
+
end
|
194
|
+
end
|
@@ -155,6 +155,22 @@ describe "Sequel::Plugins::IdentityMap" do
|
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
|
+
it "should not use the identity map as a lookup cache for a one_to_one association" do
|
159
|
+
c = @c2
|
160
|
+
@c2.one_to_one :artist, :class=>@c1, :key=>:artist_id
|
161
|
+
@c.with_identity_map do
|
162
|
+
MODEL_DB.sqls.length.should == 0
|
163
|
+
o = @c2.load(:id=>2)
|
164
|
+
a = o.artist
|
165
|
+
a.should be_a_kind_of(@c1)
|
166
|
+
MODEL_DB.sqls.length.should == 1
|
167
|
+
o.reload
|
168
|
+
MODEL_DB.sqls.length.should == 2
|
169
|
+
o.artist.should == a
|
170
|
+
MODEL_DB.sqls.length.should == 3
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
158
174
|
it "should not use the identity map as a lookup cache if the assocation has a nil :key option" do
|
159
175
|
c = @c2
|
160
176
|
@c1.many_to_one :artist, :class=>@c2, :key=>nil, :dataset=>proc{c.filter(:artist_id=>artist_id)}
|
@@ -45,9 +45,10 @@ describe "NestedAttributes plugin" do
|
|
45
45
|
@Album.columns :id, :name, :artist_id
|
46
46
|
@Tag.columns :id, :name
|
47
47
|
@Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
|
48
|
+
@Artist.one_to_one :first_album, :class=>@Album, :key=>:artist_id
|
48
49
|
@Album.many_to_one :artist, :class=>@Artist
|
49
50
|
@Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
|
50
|
-
@Artist.nested_attributes :albums, :destroy=>true, :remove=>true
|
51
|
+
@Artist.nested_attributes :albums, :first_album, :destroy=>true, :remove=>true
|
51
52
|
@Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
|
52
53
|
end
|
53
54
|
|
@@ -58,6 +59,15 @@ describe "NestedAttributes plugin" do
|
|
58
59
|
@mods.should == [[:is, :artists, {:name=>"Ar"}, 1], [:is, :albums, {:name=>"Al", :artist_id=>1}, 2]]
|
59
60
|
end
|
60
61
|
|
62
|
+
it "should support creating new one_to_one objects" do
|
63
|
+
a = @Artist.new(:name=>'Ar')
|
64
|
+
a.id = 1
|
65
|
+
a.first_album_attributes = {:name=>'Al'}
|
66
|
+
@mods.should == []
|
67
|
+
a.save
|
68
|
+
@mods.should == [[:is, :artists, {:name=>"Ar", :id=>1}, 1], [:is, :albums, {:name=>"Al"}, 2], [:u, :albums, {:artist_id=>nil}, "((artist_id = 1) AND (id != 2))"], [:u, :albums, {:name=>"Al", :artist_id=>1}, "(id = 2)"]]
|
69
|
+
end
|
70
|
+
|
61
71
|
it "should support creating new one_to_many objects" do
|
62
72
|
a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:name=>'Al'}]})
|
63
73
|
@mods.should == []
|
@@ -88,6 +98,16 @@ describe "NestedAttributes plugin" do
|
|
88
98
|
@mods.should == [[:u, :albums, {:name=>"Al"}, '(id = 10)'], [:u, :artists, {:name=>"Ar2"}, '(id = 20)']]
|
89
99
|
end
|
90
100
|
|
101
|
+
it "should support updating one_to_one objects" do
|
102
|
+
al = @Album.load(:id=>10, :name=>'Al')
|
103
|
+
ar = @Artist.load(:id=>20, :name=>'Ar')
|
104
|
+
ar.associations[:first_album] = al
|
105
|
+
ar.set(:first_album_attributes=>{:id=>10, :name=>'Al2'})
|
106
|
+
@mods.should == []
|
107
|
+
ar.save
|
108
|
+
@mods.should == [[:u, :artists, {:name=>"Ar"}, '(id = 20)'], [:u, :albums, {:name=>"Al2"}, '(id = 10)']]
|
109
|
+
end
|
110
|
+
|
91
111
|
it "should support updating one_to_many objects" do
|
92
112
|
al = @Album.load(:id=>10, :name=>'Al')
|
93
113
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
@@ -118,6 +138,17 @@ describe "NestedAttributes plugin" do
|
|
118
138
|
@mods.should == [[:u, :albums, {:artist_id=>nil, :name=>'Al'}, '(id = 10)']]
|
119
139
|
end
|
120
140
|
|
141
|
+
it "should support removing one_to_one objects" do
|
142
|
+
al = @Album.load(:id=>10, :name=>'Al')
|
143
|
+
ar = @Artist.load(:id=>20, :name=>'Ar')
|
144
|
+
ar.associations[:first_album] = al
|
145
|
+
ar.set(:first_album_attributes=>{:id=>10, :_remove=>'t'})
|
146
|
+
@mods.should == []
|
147
|
+
ar.save
|
148
|
+
@mods.should == [[:u, :albums, {:artist_id=>nil}, "(artist_id = 20)"], [:u, :artists, {:name=>"Ar"}, "(id = 20)"]]
|
149
|
+
|
150
|
+
end
|
151
|
+
|
121
152
|
it "should support removing one_to_many objects" do
|
122
153
|
al = @Album.load(:id=>10, :name=>'Al')
|
123
154
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
@@ -148,6 +179,16 @@ describe "NestedAttributes plugin" do
|
|
148
179
|
@mods.should == [[:u, :albums, {:artist_id=>nil, :name=>'Al'}, '(id = 10)'], [:d, :artists, '(id = 20)']]
|
149
180
|
end
|
150
181
|
|
182
|
+
it "should support destroying one_to_one objects" do
|
183
|
+
al = @Album.load(:id=>10, :name=>'Al')
|
184
|
+
ar = @Artist.load(:id=>20, :name=>'Ar')
|
185
|
+
ar.associations[:first_album] = al
|
186
|
+
ar.set(:first_album_attributes=>{:id=>10, :_delete=>'t'})
|
187
|
+
@mods.should == []
|
188
|
+
ar.save
|
189
|
+
@mods.should == [[:u, :albums, {:artist_id=>nil}, "(artist_id = 20)"], [:u, :artists, {:name=>"Ar"}, "(id = 20)"], [:d, :albums, "(id = 10)"]]
|
190
|
+
end
|
191
|
+
|
151
192
|
it "should support destroying one_to_many objects" do
|
152
193
|
al = @Album.load(:id=>10, :name=>'Al')
|
153
194
|
ar = @Artist.load(:id=>20, :name=>'Ar')
|
@@ -239,6 +280,8 @@ describe "NestedAttributes plugin" do
|
|
239
280
|
proc{a.save}.should raise_error(Sequel::ValidationFailed)
|
240
281
|
a.errors.full_messages.should == ['artist name cannot be Ar']
|
241
282
|
@mods.should == []
|
283
|
+
# Should preserve attributes
|
284
|
+
a.artist.name.should == 'Ar'
|
242
285
|
end
|
243
286
|
|
244
287
|
it "should not attempt to validate nested attributes if the :validate=>false association option is used" do
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, "rcte_tree" do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model(MODEL_DB[:nodes]))
|
6
|
+
@c.class_eval do
|
7
|
+
def self.name; 'Node'; end
|
8
|
+
columns :id, :name, :parent_id, :i, :pi
|
9
|
+
end
|
10
|
+
@ds = @c.dataset
|
11
|
+
class << @ds
|
12
|
+
attr_accessor :row_sets
|
13
|
+
def fetch_rows(sql)
|
14
|
+
@db << sql
|
15
|
+
row_sets.shift.each{|row| yield row}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@o = @c.load(:id=>2, :parent_id=>1, :name=>'AA', :i=>3, :pi=>4)
|
19
|
+
MODEL_DB.reset
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should define the correct associations" do
|
23
|
+
@c.plugin :rcte_tree
|
24
|
+
@c.associations.sort_by{|x| x.to_s}.should == [:ancestors, :children, :descendants, :parent]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should define the correct associations when giving options" do
|
28
|
+
@c.plugin :rcte_tree, :ancestors=>{:name=>:as}, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}, :parent=>{:name=>:p}
|
29
|
+
@c.associations.sort_by{|x| x.to_s}.should == [:as, :cs, :ds, :p]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should use the correct SQL for lazy associations" do
|
33
|
+
@c.plugin :rcte_tree
|
34
|
+
@o.parent_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1'
|
35
|
+
@o.children_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.parent_id = 2)'
|
36
|
+
@o.ancestors_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE (id = 1) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.parent_id = nodes.id)) SELECT * FROM t'
|
37
|
+
@o.descendants_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE (parent_id = 2) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should use the correct SQL for lazy associations when giving options" do
|
41
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :cte_name=>:cte, :order=>:name, :ancestors=>{:name=>:as}, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}, :parent=>{:name=>:p}
|
42
|
+
@o.p_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.i = 4) ORDER BY name LIMIT 1'
|
43
|
+
@o.cs_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.pi = 3) ORDER BY name'
|
44
|
+
@o.as_dataset.sql.should == 'WITH cte AS (SELECT * FROM nodes WHERE (i = 4) UNION ALL SELECT nodes.* FROM nodes INNER JOIN cte ON (cte.pi = nodes.i)) SELECT * FROM cte ORDER BY name'
|
45
|
+
@o.ds_dataset.sql.should == 'WITH cte AS (SELECT * FROM nodes WHERE (pi = 3) UNION ALL SELECT nodes.* FROM nodes INNER JOIN cte ON (cte.i = nodes.pi)) SELECT * FROM cte ORDER BY name'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should add all parent associations when lazily loading ancestors" do
|
49
|
+
@c.plugin :rcte_tree
|
50
|
+
@ds.row_sets = [[{:id=>1, :name=>'A', :parent_id=>3}, {:id=>4, :name=>'B', :parent_id=>nil}, {:id=>3, :name=>'?', :parent_id=>4}]]
|
51
|
+
@o.ancestors.should == [@c.load(:id=>1, :name=>'A', :parent_id=>3), @c.load(:id=>4, :name=>'B', :parent_id=>nil), @c.load(:id=>3, :name=>'?', :parent_id=>4)]
|
52
|
+
@o.associations[:parent].should == @c.load(:id=>1, :name=>'A', :parent_id=>3)
|
53
|
+
@o.associations[:parent].associations[:parent].should == @c.load(:id=>3, :name=>'?', :parent_id=>4)
|
54
|
+
@o.associations[:parent].associations[:parent].associations[:parent].should == @c.load(:id=>4, :name=>'B', :parent_id=>nil)
|
55
|
+
@o.associations[:parent].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should add all parent associations when lazily loading ancestors and giving options" do
|
59
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :ancestors=>{:name=>:as}, :parent=>{:name=>:p}
|
60
|
+
@ds.row_sets = [[{:i=>4, :name=>'A', :pi=>5}, {:i=>6, :name=>'B', :pi=>nil}, {:i=>5, :name=>'?', :pi=>6}]]
|
61
|
+
@o.as.should == [@c.load(:i=>4, :name=>'A', :pi=>5), @c.load(:i=>6, :name=>'B', :pi=>nil), @c.load(:i=>5, :name=>'?', :pi=>6)]
|
62
|
+
@o.associations[:p].should == @c.load(:i=>4, :name=>'A', :pi=>5)
|
63
|
+
@o.associations[:p].associations[:p].should == @c.load(:i=>5, :name=>'?', :pi=>6)
|
64
|
+
@o.associations[:p].associations[:p].associations[:p].should == @c.load(:i=>6, :name=>'B', :pi=>nil)
|
65
|
+
@o.associations[:p].associations[:p].associations[:p].associations.fetch(:p, 1).should == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should add all children associations when lazily loading descendants" do
|
69
|
+
@c.plugin :rcte_tree
|
70
|
+
@ds.row_sets = [[{:id=>3, :name=>'??', :parent_id=>1}, {:id=>1, :name=>'A', :parent_id=>2}, {:id=>4, :name=>'B', :parent_id=>2}, {:id=>5, :name=>'?', :parent_id=>3}]]
|
71
|
+
@o.descendants.should == [@c.load(:id=>3, :name=>'??', :parent_id=>1), @c.load(:id=>1, :name=>'A', :parent_id=>2), @c.load(:id=>4, :name=>'B', :parent_id=>2), @c.load(:id=>5, :name=>'?', :parent_id=>3)]
|
72
|
+
@o.associations[:children].should == [@c.load(:id=>1, :name=>'A', :parent_id=>2), @c.load(:id=>4, :name=>'B', :parent_id=>2)]
|
73
|
+
@o.associations[:children].map{|c1| c1.associations[:children]}.should == [[@c.load(:id=>3, :name=>'??', :parent_id=>1)], []]
|
74
|
+
@o.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@c.load(:id=>5, :name=>'?', :parent_id=>3)]], []]
|
75
|
+
@o.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children]}}}.should == [[[[]]], []]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should add all children associations when lazily loading descendants and giving options" do
|
79
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
|
80
|
+
@ds.row_sets = [[{:i=>7, :name=>'??', :pi=>5}, {:i=>5, :name=>'A', :pi=>3}, {:i=>6, :name=>'B', :pi=>3}, {:i=>8, :name=>'?', :pi=>7}]]
|
81
|
+
@o.ds.should == [@c.load(:i=>7, :name=>'??', :pi=>5), @c.load(:i=>5, :name=>'A', :pi=>3), @c.load(:i=>6, :name=>'B', :pi=>3), @c.load(:i=>8, :name=>'?', :pi=>7)]
|
82
|
+
@o.associations[:cs].should == [@c.load(:i=>5, :name=>'A', :pi=>3), @c.load(:i=>6, :name=>'B', :pi=>3)]
|
83
|
+
@o.associations[:cs].map{|c1| c1.associations[:cs]}.should == [[@c.load(:i=>7, :name=>'??', :pi=>5)], []]
|
84
|
+
@o.associations[:cs].map{|c1| c1.associations[:cs].map{|c2| c2.associations[:cs]}}.should == [[[@c.load(:i=>8, :name=>'?', :pi=>7)]], []]
|
85
|
+
@o.associations[:cs].map{|c1| c1.associations[:cs].map{|c2| c2.associations[:cs].map{|c3| c3.associations[:cs]}}}.should == [[[[]]], []]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should eagerly load ancestors" do
|
89
|
+
@c.plugin :rcte_tree
|
90
|
+
@ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}, {:id=>9, :parent_id=>nil, :name=>'E'}],
|
91
|
+
[{:id=>2, :name=>'AA', :parent_id=>1, :x_root_x=>2},
|
92
|
+
{:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>1}, {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>2},
|
93
|
+
{:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>2}, {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>1}]]
|
94
|
+
os = @ds.eager(:ancestors).all
|
95
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
96
|
+
MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x, nodes\.\* FROM nodes WHERE \(id IN \([12], [12]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.parent_id = nodes\.id\)\) SELECT \* FROM t/
|
97
|
+
os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D'), @c.load(:id=>9, :parent_id=>nil, :name=>'E')]
|
98
|
+
os.map{|o| o.ancestors}.should == [[@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
|
99
|
+
[@c.load(:id=>2, :name=>'AA', :parent_id=>1), @c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
|
100
|
+
[@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
|
101
|
+
[]]
|
102
|
+
os.map{|o| o.parent}.should == [@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>2, :name=>'AA', :parent_id=>1), @c.load(:id=>1, :name=>'00', :parent_id=>8), nil]
|
103
|
+
os.map{|o| o.parent.parent if o.parent}.should == [@c.load(:id=>8, :name=>'?', :parent_id=>nil), @c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil]
|
104
|
+
os.map{|o| o.parent.parent.parent if o.parent and o.parent.parent}.should == [nil, @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil, nil]
|
105
|
+
os.map{|o| o.parent.parent.parent.parent if o.parent and o.parent.parent and o.parent.parent.parent}.should == [nil, nil, nil, nil]
|
106
|
+
MODEL_DB.new_sqls.should == []
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should eagerly load ancestors when giving options" do
|
110
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :cte_name=>:cte, :ancestors=>{:name=>:as}, :parent=>{:name=>:p}
|
111
|
+
@ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}, {:i=>9, :pi=>nil, :name=>'E'}],
|
112
|
+
[{:i=>2, :name=>'AA', :pi=>1, :kal=>2},
|
113
|
+
{:i=>1, :name=>'00', :pi=>8, :kal=>1}, {:i=>1, :name=>'00', :pi=>8, :kal=>2},
|
114
|
+
{:i=>8, :name=>'?', :pi=>nil, :kal=>2}, {:i=>8, :name=>'?', :pi=>nil, :kal=>1}]]
|
115
|
+
os = @ds.eager(:as).all
|
116
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
117
|
+
MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT i AS kal, nodes\.\* FROM nodes WHERE \(i IN \([12], [12]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.pi = nodes\.i\)\) SELECT \* FROM cte/
|
118
|
+
os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D'), @c.load(:i=>9, :pi=>nil, :name=>'E')]
|
119
|
+
os.map{|o| o.as}.should == [[@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
|
120
|
+
[@c.load(:i=>2, :name=>'AA', :pi=>1), @c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
|
121
|
+
[@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
|
122
|
+
[]]
|
123
|
+
os.map{|o| o.p}.should == [@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>2, :name=>'AA', :pi=>1), @c.load(:i=>1, :name=>'00', :pi=>8), nil]
|
124
|
+
os.map{|o| o.p.p if o.p}.should == [@c.load(:i=>8, :name=>'?', :pi=>nil), @c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil), nil]
|
125
|
+
os.map{|o| o.p.p.p if o.p and o.p.p}.should == [nil, @c.load(:i=>8, :name=>'?', :pi=>nil), nil, nil]
|
126
|
+
os.map{|o| o.p.p.p.p if o.p and o.p.p and o.p.p.p}.should == [nil, nil, nil, nil]
|
127
|
+
MODEL_DB.new_sqls.should == []
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should eagerly load descendants" do
|
131
|
+
@c.plugin :rcte_tree
|
132
|
+
@ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}],
|
133
|
+
[{:id=>6, :parent_id=>2, :name=>'C', :x_root_x=>2}, {:id=>9, :parent_id=>2, :name=>'E', :x_root_x=>2},
|
134
|
+
{:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2},
|
135
|
+
{:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7}]]
|
136
|
+
os = @ds.eager(:descendants).all
|
137
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
138
|
+
MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\* FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\)\) SELECT \* FROM t/
|
139
|
+
os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
|
140
|
+
os.map{|o| o.descendants}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E'), @c.load(:id=>3, :name=>'00', :parent_id=>6)],
|
141
|
+
[@c.load(:id=>3, :name=>'00', :parent_id=>6)],
|
142
|
+
[@c.load(:id=>4, :name=>'?', :parent_id=>7), @c.load(:id=>5, :name=>'?', :parent_id=>4)]]
|
143
|
+
os.map{|o| o.children}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
|
144
|
+
os.map{|o1| o1.children.map{|o2| o2.children}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
|
145
|
+
os.map{|o1| o1.children.map{|o2| o2.children.map{|o3| o3.children}}}.should == [[[[]], []], [[]], [[[]]]]
|
146
|
+
MODEL_DB.new_sqls.should == []
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should eagerly load descendants when giving options" do
|
150
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :cte_name=>:cte, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
|
151
|
+
@ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}],
|
152
|
+
[{:i=>6, :pi=>2, :name=>'C', :kal=>2}, {:i=>9, :pi=>2, :name=>'E', :kal=>2},
|
153
|
+
{:i=>3, :name=>'00', :pi=>6, :kal=>6}, {:i=>3, :name=>'00', :pi=>6, :kal=>2},
|
154
|
+
{:i=>4, :name=>'?', :pi=>7, :kal=>7}, {:i=>5, :name=>'?', :pi=>4, :kal=>7}]]
|
155
|
+
os = @ds.eager(:ds).all
|
156
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
157
|
+
MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\* FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\)\) SELECT \* FROM cte/
|
158
|
+
os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
|
159
|
+
os.map{|o| o.ds}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E'), @c.load(:i=>3, :name=>'00', :pi=>6)],
|
160
|
+
[@c.load(:i=>3, :name=>'00', :pi=>6)],
|
161
|
+
[@c.load(:i=>4, :name=>'?', :pi=>7), @c.load(:i=>5, :name=>'?', :pi=>4)]]
|
162
|
+
os.map{|o| o.cs}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
|
163
|
+
os.map{|o1| o1.cs.map{|o2| o2.cs}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
|
164
|
+
os.map{|o1| o1.cs.map{|o2| o2.cs.map{|o3| o3.cs}}}.should == [[[[]], []], [[]], [[[]]]]
|
165
|
+
MODEL_DB.new_sqls.should == []
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should eagerly load descendants to a given level" do
|
169
|
+
@c.plugin :rcte_tree
|
170
|
+
@ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}],
|
171
|
+
[{:id=>6, :parent_id=>2, :name=>'C', :x_root_x=>2, :x_level_x=>0}, {:id=>9, :parent_id=>2, :name=>'E', :x_root_x=>2, :x_level_x=>0},
|
172
|
+
{:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6, :x_level_x=>0}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2, :x_level_x=>1},
|
173
|
+
{:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7, :x_level_x=>0}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7, :x_level_x=>1}]]
|
174
|
+
os = @ds.eager(:descendants=>2).all
|
175
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
176
|
+
MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\*, 0 AS x_level_x FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\*, \(t\.x_level_x \+ 1\) AS x_level_x FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\) WHERE \(t\.x_level_x < 1\)\) SELECT \* FROM t/
|
177
|
+
os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
|
178
|
+
os.map{|o| o.descendants}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E'), @c.load(:id=>3, :name=>'00', :parent_id=>6)],
|
179
|
+
[@c.load(:id=>3, :name=>'00', :parent_id=>6)],
|
180
|
+
[@c.load(:id=>4, :name=>'?', :parent_id=>7), @c.load(:id=>5, :name=>'?', :parent_id=>4)]]
|
181
|
+
os.map{|o| o.associations[:children]}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
|
182
|
+
os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children]}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
|
183
|
+
os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children].map{|o3| o3.associations[:children]}}}.should == [[[[]], []], [[]], [[nil]]]
|
184
|
+
MODEL_DB.new_sqls.should == []
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should eagerly load descendants to a given level when giving options" do
|
188
|
+
@c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :level_alias=>:lal, :cte_name=>:cte, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
|
189
|
+
@ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}],
|
190
|
+
[{:i=>6, :pi=>2, :name=>'C', :kal=>2, :lal=>0}, {:i=>9, :pi=>2, :name=>'E', :kal=>2, :lal=>0},
|
191
|
+
{:i=>3, :name=>'00', :pi=>6, :kal=>6, :lal=>0}, {:i=>3, :name=>'00', :pi=>6, :kal=>2, :lal=>1},
|
192
|
+
{:i=>4, :name=>'?', :pi=>7, :kal=>7, :lal=>0}, {:i=>5, :name=>'?', :pi=>4, :kal=>7, :lal=>1}]]
|
193
|
+
os = @ds.eager(:ds=>2).all
|
194
|
+
MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
|
195
|
+
MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\*, 0 AS lal FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\*, \(cte\.lal \+ 1\) AS lal FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\) WHERE \(cte\.lal < 1\)\) SELECT \* FROM cte/
|
196
|
+
os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
|
197
|
+
os.map{|o| o.ds}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E'), @c.load(:i=>3, :name=>'00', :pi=>6)],
|
198
|
+
[@c.load(:i=>3, :name=>'00', :pi=>6)],
|
199
|
+
[@c.load(:i=>4, :name=>'?', :pi=>7), @c.load(:i=>5, :name=>'?', :pi=>4)]]
|
200
|
+
os.map{|o| o.associations[:cs]}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
|
201
|
+
os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs]}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
|
202
|
+
os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs].map{|o3| o3.associations[:cs]}}}.should == [[[[]], []], [[]], [[nil]]]
|
203
|
+
MODEL_DB.new_sqls.should == []
|
204
|
+
end
|
205
|
+
end
|