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
@@ -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
|