viking-sequel 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 +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,1391 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, "#eager" do
|
4
|
+
before(:each) do
|
5
|
+
MODEL_DB.reset
|
6
|
+
|
7
|
+
class ::EagerAlbum < Sequel::Model(:albums)
|
8
|
+
columns :id, :band_id
|
9
|
+
many_to_one :band, :class=>'EagerBand', :key=>:band_id
|
10
|
+
one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id
|
11
|
+
many_to_many :genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
12
|
+
one_to_many :good_tracks, :class=>'EagerTrack', :key=>:album_id do |ds|
|
13
|
+
ds.filter(:name=>'Good')
|
14
|
+
end
|
15
|
+
many_to_one :band_name, :class=>'EagerBand', :key=>:band_id, :select=>[:id, :name]
|
16
|
+
one_to_many :track_names, :class=>'EagerTrack', :key=>:album_id, :select=>[:id, :name]
|
17
|
+
many_to_many :genre_names, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :select=>[:id]
|
18
|
+
end
|
19
|
+
|
20
|
+
class ::EagerBand < Sequel::Model(:bands)
|
21
|
+
columns :id, :p_k
|
22
|
+
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
|
23
|
+
one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks
|
24
|
+
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
25
|
+
many_to_many :graph_members, :clone=>:members, :eager_graph=>:bands
|
26
|
+
one_to_many :good_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_block=>proc{|ds| ds.filter(:name=>'good')} do |ds|
|
27
|
+
ds.filter(:name=>'Good')
|
28
|
+
end
|
29
|
+
one_to_many :self_titled_albums, :class=>'EagerAlbum', :key=>:band_id, :allow_eager=>false do |ds|
|
30
|
+
ds.filter(:name=>name)
|
31
|
+
end
|
32
|
+
one_to_many :albums_by_name, :class=>'EagerAlbum', :key=>:band_id, :order=>:name, :allow_eager=>false
|
33
|
+
one_to_many :top_10_albums, :class=>'EagerAlbum', :key=>:band_id, :limit=>10
|
34
|
+
end
|
35
|
+
|
36
|
+
class ::EagerTrack < Sequel::Model(:tracks)
|
37
|
+
columns :id, :album_id
|
38
|
+
many_to_one :album, :class=>'EagerAlbum', :key=>:album_id
|
39
|
+
end
|
40
|
+
|
41
|
+
class ::EagerGenre < Sequel::Model(:genres)
|
42
|
+
columns :id, :xxx
|
43
|
+
many_to_many :albums, :class=>'EagerAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
44
|
+
end
|
45
|
+
|
46
|
+
class ::EagerBandMember < Sequel::Model(:members)
|
47
|
+
columns :id
|
48
|
+
many_to_many :bands, :class=>'EagerBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm, :order =>:id
|
49
|
+
end
|
50
|
+
|
51
|
+
EagerAlbum.dataset.extend(Module.new {
|
52
|
+
def columns
|
53
|
+
[:id, :band_id]
|
54
|
+
end
|
55
|
+
|
56
|
+
def fetch_rows(sql)
|
57
|
+
h = if sql =~ /101/
|
58
|
+
{:id => 101, :band_id=> 101}
|
59
|
+
else
|
60
|
+
{:id => 1, :band_id=> 2}
|
61
|
+
end
|
62
|
+
h.merge!(:x_foreign_key_x=>4) if sql =~ /ag\.genre_id/
|
63
|
+
@db << sql
|
64
|
+
yield h
|
65
|
+
end
|
66
|
+
})
|
67
|
+
|
68
|
+
EagerBand.dataset.extend(Module.new {
|
69
|
+
def fetch_rows(sql)
|
70
|
+
h = {:id => 2}
|
71
|
+
h.merge!(:x_foreign_key_x=>5) if sql =~ /bm\.member_id/
|
72
|
+
@db << sql
|
73
|
+
case sql
|
74
|
+
when /id IN (101)/
|
75
|
+
when /id > 100/
|
76
|
+
yield({:id => 101})
|
77
|
+
yield({:id => 102})
|
78
|
+
else
|
79
|
+
yield h
|
80
|
+
end
|
81
|
+
end
|
82
|
+
})
|
83
|
+
|
84
|
+
EagerTrack.dataset.extend(Module.new {
|
85
|
+
def fetch_rows(sql)
|
86
|
+
@db << sql
|
87
|
+
yield({:id => 3, :album_id => 1})
|
88
|
+
end
|
89
|
+
})
|
90
|
+
|
91
|
+
EagerGenre.dataset.extend(Module.new {
|
92
|
+
def fetch_rows(sql)
|
93
|
+
h = {:id => 4}
|
94
|
+
h.merge!(:x_foreign_key_x=>1) if sql =~ /ag\.album_id/
|
95
|
+
@db << sql
|
96
|
+
yield h
|
97
|
+
end
|
98
|
+
})
|
99
|
+
|
100
|
+
EagerBandMember.dataset.extend(Module.new {
|
101
|
+
def fetch_rows(sql)
|
102
|
+
h = {:id => 5}
|
103
|
+
h.merge!(:x_foreign_key_x=>2) if sql =~ /bm\.band_id/
|
104
|
+
@db << sql
|
105
|
+
yield h
|
106
|
+
end
|
107
|
+
})
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should raise an error if called without a symbol or hash" do
|
111
|
+
proc{EagerAlbum.eager(Object.new)}.should raise_error(Sequel::Error)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should eagerly load a single many_to_one association" do
|
115
|
+
a = EagerAlbum.eager(:band).all
|
116
|
+
a.should be_a_kind_of(Array)
|
117
|
+
a.size.should == 1
|
118
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
119
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
120
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
|
121
|
+
a = a.first
|
122
|
+
a.band.should be_a_kind_of(EagerBand)
|
123
|
+
a.band.values.should == {:id => 2}
|
124
|
+
MODEL_DB.sqls.length.should == 2
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should eagerly load a single one_to_one association" do
|
128
|
+
EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
|
129
|
+
a = EagerAlbum.eager(:track).all
|
130
|
+
a.should == [EagerAlbum.load(:id => 1, :band_id => 2)]
|
131
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
132
|
+
a.first.track.should == EagerTrack.load(:id => 3, :album_id=>1)
|
133
|
+
MODEL_DB.sqls.length.should == 2
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should eagerly load a single one_to_many association" do
|
137
|
+
a = EagerAlbum.eager(:tracks).all
|
138
|
+
a.should be_a_kind_of(Array)
|
139
|
+
a.size.should == 1
|
140
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
141
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
142
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
143
|
+
a = a.first
|
144
|
+
a.tracks.should be_a_kind_of(Array)
|
145
|
+
a.tracks.size.should == 1
|
146
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
147
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
148
|
+
MODEL_DB.sqls.length.should == 2
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should eagerly load a single many_to_many association" do
|
152
|
+
a = EagerAlbum.eager(:genres).all
|
153
|
+
a.should be_a_kind_of(Array)
|
154
|
+
a.size.should == 1
|
155
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
156
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
157
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
158
|
+
a = a.first
|
159
|
+
a.genres.should be_a_kind_of(Array)
|
160
|
+
a.genres.size.should == 1
|
161
|
+
a.genres.first.should be_a_kind_of(EagerGenre)
|
162
|
+
a.genres.first.values.should == {:id => 4}
|
163
|
+
MODEL_DB.sqls.length.should == 2
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should eagerly load multiple associations in a single call" do
|
167
|
+
a = EagerAlbum.eager(:genres, :tracks, :band).all
|
168
|
+
a.should be_a_kind_of(Array)
|
169
|
+
a.size.should == 1
|
170
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
171
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
172
|
+
MODEL_DB.sqls.length.should == 4
|
173
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
174
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (bands.id IN (2))'))
|
175
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (tracks.album_id IN (1))'))
|
176
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))'))
|
177
|
+
a = a.first
|
178
|
+
a.band.should be_a_kind_of(EagerBand)
|
179
|
+
a.band.values.should == {:id => 2}
|
180
|
+
a.tracks.should be_a_kind_of(Array)
|
181
|
+
a.tracks.size.should == 1
|
182
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
183
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
184
|
+
a.genres.should be_a_kind_of(Array)
|
185
|
+
a.genres.size.should == 1
|
186
|
+
a.genres.first.should be_a_kind_of(EagerGenre)
|
187
|
+
a.genres.first.values.should == {:id => 4}
|
188
|
+
MODEL_DB.sqls.length.should == 4
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should eagerly load multiple associations in separate calls" do
|
192
|
+
a = EagerAlbum.eager(:genres).eager(:tracks).eager(:band).all
|
193
|
+
a.should be_a_kind_of(Array)
|
194
|
+
a.size.should == 1
|
195
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
196
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
197
|
+
MODEL_DB.sqls.length.should == 4
|
198
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
199
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (bands.id IN (2))'))
|
200
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (tracks.album_id IN (1))'))
|
201
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))'))
|
202
|
+
a = a.first
|
203
|
+
a.band.should be_a_kind_of(EagerBand)
|
204
|
+
a.band.values.should == {:id => 2}
|
205
|
+
a.tracks.should be_a_kind_of(Array)
|
206
|
+
a.tracks.size.should == 1
|
207
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
208
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
209
|
+
a.genres.should be_a_kind_of(Array)
|
210
|
+
a.genres.size.should == 1
|
211
|
+
a.genres.first.should be_a_kind_of(EagerGenre)
|
212
|
+
a.genres.first.values.should == {:id => 4}
|
213
|
+
MODEL_DB.sqls.length.should == 4
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should allow cascading of eager loading for associations of associated models" do
|
217
|
+
a = EagerTrack.eager(:album=>{:band=>:members}).all
|
218
|
+
a.should be_a_kind_of(Array)
|
219
|
+
a.size.should == 1
|
220
|
+
a.first.should be_a_kind_of(EagerTrack)
|
221
|
+
a.first.values.should == {:id => 3, :album_id => 1}
|
222
|
+
MODEL_DB.sqls.length.should == 4
|
223
|
+
MODEL_DB.sqls.should == ['SELECT * FROM tracks',
|
224
|
+
'SELECT * FROM albums WHERE (albums.id IN (1))',
|
225
|
+
'SELECT * FROM bands WHERE (bands.id IN (2))',
|
226
|
+
"SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON ((bm.member_id = members.id) AND (bm.band_id IN (2)))"]
|
227
|
+
a = a.first
|
228
|
+
a.album.should be_a_kind_of(EagerAlbum)
|
229
|
+
a.album.values.should == {:id => 1, :band_id => 2}
|
230
|
+
a.album.band.should be_a_kind_of(EagerBand)
|
231
|
+
a.album.band.values.should == {:id => 2}
|
232
|
+
a.album.band.members.should be_a_kind_of(Array)
|
233
|
+
a.album.band.members.size.should == 1
|
234
|
+
a.album.band.members.first.should be_a_kind_of(EagerBandMember)
|
235
|
+
a.album.band.members.first.values.should == {:id => 5}
|
236
|
+
MODEL_DB.sqls.length.should == 4
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should cascade eagerly loading when the :eager association option is used" do
|
240
|
+
a = EagerBand.eager(:albums).all
|
241
|
+
a.should be_a_kind_of(Array)
|
242
|
+
a.size.should == 1
|
243
|
+
a.first.should be_a_kind_of(EagerBand)
|
244
|
+
a.first.values.should == {:id => 2}
|
245
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
246
|
+
'SELECT * FROM albums WHERE (albums.band_id IN (2))',
|
247
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
248
|
+
a = a.first
|
249
|
+
a.albums.should be_a_kind_of(Array)
|
250
|
+
a.albums.size.should == 1
|
251
|
+
a.albums.first.should be_a_kind_of(EagerAlbum)
|
252
|
+
a.albums.first.values.should == {:id => 1, :band_id => 2}
|
253
|
+
a = a.albums.first
|
254
|
+
a.tracks.should be_a_kind_of(Array)
|
255
|
+
a.tracks.size.should == 1
|
256
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
257
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
258
|
+
MODEL_DB.sqls.length.should == 3
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should respect :eager when lazily loading an association" do
|
262
|
+
a = EagerBand.all
|
263
|
+
a.should be_a_kind_of(Array)
|
264
|
+
a.size.should == 1
|
265
|
+
a.first.should be_a_kind_of(EagerBand)
|
266
|
+
a.first.values.should == {:id => 2}
|
267
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands']
|
268
|
+
a = a.first
|
269
|
+
a.albums
|
270
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
271
|
+
'SELECT * FROM albums WHERE (albums.band_id = 2)',
|
272
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
273
|
+
a.albums.should be_a_kind_of(Array)
|
274
|
+
a.albums.size.should == 1
|
275
|
+
a.albums.first.should be_a_kind_of(EagerAlbum)
|
276
|
+
a.albums.first.values.should == {:id => 1, :band_id => 2}
|
277
|
+
a = a.albums.first
|
278
|
+
a.tracks.should be_a_kind_of(Array)
|
279
|
+
a.tracks.size.should == 1
|
280
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
281
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
282
|
+
MODEL_DB.sqls.length.should == 3
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should cascade eagerly loading when the :eager_graph association option is used" do
|
286
|
+
EagerAlbum.dataset.extend(Module.new {
|
287
|
+
def fetch_rows(sql)
|
288
|
+
@db << sql
|
289
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
290
|
+
end
|
291
|
+
})
|
292
|
+
a = EagerBand.eager(:graph_albums).all
|
293
|
+
a.should be_a_kind_of(Array)
|
294
|
+
a.size.should == 1
|
295
|
+
a.first.should be_a_kind_of(EagerBand)
|
296
|
+
a.first.values.should == {:id => 2}
|
297
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
298
|
+
'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id IN (2))']
|
299
|
+
a = a.first
|
300
|
+
a.graph_albums.should be_a_kind_of(Array)
|
301
|
+
a.graph_albums.size.should == 1
|
302
|
+
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
|
303
|
+
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
|
304
|
+
a = a.graph_albums.first
|
305
|
+
a.tracks.should be_a_kind_of(Array)
|
306
|
+
a.tracks.size.should == 1
|
307
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
308
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
309
|
+
MODEL_DB.sqls.length.should == 2
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should cascade eagerly loading when the :eager_graph association option is used with a many_to_many association" do
|
313
|
+
EagerBandMember.dataset.extend(Module.new {
|
314
|
+
def columns
|
315
|
+
[:id]
|
316
|
+
end
|
317
|
+
def fetch_rows(sql)
|
318
|
+
@db << sql
|
319
|
+
yield({:id=>5, :bands_id=>2, :p_k=>6, :x_foreign_key_x=>2})
|
320
|
+
yield({:id=>5, :bands_id=>3, :p_k=>6, :x_foreign_key_x=>2})
|
321
|
+
end
|
322
|
+
})
|
323
|
+
a = EagerBand.eager(:graph_members).all
|
324
|
+
a.should == [EagerBand.load(:id=>2)]
|
325
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
326
|
+
'SELECT members.id, bands.id AS bands_id, bands.p_k, bm.band_id AS x_foreign_key_x FROM (SELECT members.* FROM members INNER JOIN bm ON ((bm.member_id = members.id) AND (bm.band_id IN (2)))) AS members LEFT OUTER JOIN bm AS bm_0 ON (bm_0.member_id = members.id) LEFT OUTER JOIN bands ON (bands.id = bm_0.band_id) ORDER BY bands.id']
|
327
|
+
a = a.first
|
328
|
+
a.graph_members.should == [EagerBandMember.load(:id=>5)]
|
329
|
+
a.graph_members.first.bands.should == [EagerBand.load(:id=>2, :p_k=>6), EagerBand.load(:id=>3, :p_k=>6)]
|
330
|
+
MODEL_DB.sqls.length.should == 2
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should respect :eager_graph when lazily loading an association" do
|
334
|
+
a = EagerBand.all
|
335
|
+
a.should be_a_kind_of(Array)
|
336
|
+
a.size.should == 1
|
337
|
+
a.first.should be_a_kind_of(EagerBand)
|
338
|
+
a.first.values.should == {:id => 2}
|
339
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands']
|
340
|
+
a = a.first
|
341
|
+
EagerAlbum.dataset.extend(Module.new {
|
342
|
+
def fetch_rows(sql)
|
343
|
+
@db << sql
|
344
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
345
|
+
end
|
346
|
+
})
|
347
|
+
a.graph_albums
|
348
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands',
|
349
|
+
'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id = 2)']
|
350
|
+
a.graph_albums.should be_a_kind_of(Array)
|
351
|
+
a.graph_albums.size.should == 1
|
352
|
+
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
|
353
|
+
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
|
354
|
+
a = a.graph_albums.first
|
355
|
+
a.tracks.should be_a_kind_of(Array)
|
356
|
+
a.tracks.size.should == 1
|
357
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
358
|
+
a.tracks.first.values.should == {:id => 3, :album_id => 1}
|
359
|
+
MODEL_DB.sqls.length.should == 2
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should respect :eager_graph when lazily loading a many_to_many association" do
|
363
|
+
EagerBandMember.dataset.extend(Module.new {
|
364
|
+
def columns
|
365
|
+
[:id]
|
366
|
+
end
|
367
|
+
def fetch_rows(sql)
|
368
|
+
@db << sql
|
369
|
+
yield({:id=>5, :bands_id=>2, :p_k=>6})
|
370
|
+
yield({:id=>5, :bands_id=>3, :p_k=>6})
|
371
|
+
end
|
372
|
+
})
|
373
|
+
a = EagerBand.load(:id=>2)
|
374
|
+
a.graph_members.should == [EagerBandMember.load(:id=>5)]
|
375
|
+
MODEL_DB.sqls.should == ['SELECT members.id, bands.id AS bands_id, bands.p_k FROM (SELECT members.* FROM members INNER JOIN bm ON ((bm.member_id = members.id) AND (bm.band_id = 2))) AS members LEFT OUTER JOIN bm AS bm_0 ON (bm_0.member_id = members.id) LEFT OUTER JOIN bands ON (bands.id = bm_0.band_id) ORDER BY bands.id']
|
376
|
+
a.graph_members.first.bands.should == [EagerBand.load(:id=>2, :p_k=>6), EagerBand.load(:id=>3, :p_k=>6)]
|
377
|
+
MODEL_DB.sqls.length.should == 1
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should respect :conditions when eagerly loading" do
|
381
|
+
EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>{:a=>32}
|
382
|
+
a = EagerBandMember.eager(:good_bands).all
|
383
|
+
a.should be_a_kind_of(Array)
|
384
|
+
a.size.should == 1
|
385
|
+
a.first.should be_a_kind_of(EagerBandMember)
|
386
|
+
a.first.values.should == {:id => 5}
|
387
|
+
MODEL_DB.sqls.should == ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON ((bm.band_id = bands.id) AND (bm.member_id IN (5))) WHERE (a = 32) ORDER BY id']
|
388
|
+
a = a.first
|
389
|
+
a.good_bands.should be_a_kind_of(Array)
|
390
|
+
a.good_bands.size.should == 1
|
391
|
+
a.good_bands.first.should be_a_kind_of(EagerBand)
|
392
|
+
a.good_bands.first.values.should == {:id => 2}
|
393
|
+
MODEL_DB.sqls.length.should == 2
|
394
|
+
|
395
|
+
MODEL_DB.sqls.clear
|
396
|
+
EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>"x = 1"
|
397
|
+
a = EagerBandMember.eager(:good_bands).all
|
398
|
+
MODEL_DB.sqls.should == ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON ((bm.band_id = bands.id) AND (bm.member_id IN (5))) WHERE (x = 1) ORDER BY id']
|
399
|
+
end
|
400
|
+
|
401
|
+
it "should respect :order when eagerly loading" do
|
402
|
+
a = EagerBandMember.eager(:bands).all
|
403
|
+
a.should be_a_kind_of(Array)
|
404
|
+
a.size.should == 1
|
405
|
+
a.first.should be_a_kind_of(EagerBandMember)
|
406
|
+
a.first.values.should == {:id => 5}
|
407
|
+
MODEL_DB.sqls.should == ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON ((bm.band_id = bands.id) AND (bm.member_id IN (5))) ORDER BY id']
|
408
|
+
a = a.first
|
409
|
+
a.bands.should be_a_kind_of(Array)
|
410
|
+
a.bands.size.should == 1
|
411
|
+
a.bands.first.should be_a_kind_of(EagerBand)
|
412
|
+
a.bands.first.values.should == {:id => 2}
|
413
|
+
MODEL_DB.sqls.length.should == 2
|
414
|
+
end
|
415
|
+
|
416
|
+
it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
|
417
|
+
a = EagerAlbum.eager(:tracks).all
|
418
|
+
a.should be_a_kind_of(Array)
|
419
|
+
a.size.should == 1
|
420
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
421
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
422
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
|
423
|
+
a = a.first
|
424
|
+
a.tracks.should be_a_kind_of(Array)
|
425
|
+
a.tracks.size.should == 1
|
426
|
+
a.tracks.first.should be_a_kind_of(EagerTrack)
|
427
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
428
|
+
a.tracks.first.album.should be_a_kind_of(EagerAlbum)
|
429
|
+
a.tracks.first.album.should == a
|
430
|
+
MODEL_DB.sqls.length.should == 2
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should cache the negative lookup when eagerly loading a many_to_one association" do
|
434
|
+
a = EagerAlbum.eager(:band).filter(:id=>101).all
|
435
|
+
a.should be_a_kind_of(Array)
|
436
|
+
a.size.should == 1
|
437
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
438
|
+
a.first.values.should == {:id => 101, :band_id => 101}
|
439
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums WHERE (id = 101)', 'SELECT * FROM bands WHERE (bands.id IN (101))']
|
440
|
+
a = a.first
|
441
|
+
a.associations.fetch(:band, 2).should == nil
|
442
|
+
a.band.should == nil
|
443
|
+
MODEL_DB.sqls.length.should == 2
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should cache the negative lookup when eagerly loading a *_to_many associations" do
|
447
|
+
a = EagerBand.eager(:albums).filter('id > 100').all
|
448
|
+
a.should be_a_kind_of(Array)
|
449
|
+
a.size.should == 2
|
450
|
+
a.first.should be_a_kind_of(EagerBand)
|
451
|
+
a.first.values.should == {:id => 101}
|
452
|
+
a.last.values.should == {:id => 102}
|
453
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands WHERE (id > 100)', 'SELECT * FROM albums WHERE (albums.band_id IN (101, 102))', "SELECT * FROM tracks WHERE (tracks.album_id IN (101))"]
|
454
|
+
a.first.associations[:albums].should be_a_kind_of(Array)
|
455
|
+
a.first.albums.length.should == 1
|
456
|
+
a.first.albums.first.should be_a_kind_of(EagerAlbum)
|
457
|
+
a.last.associations[:albums].should == []
|
458
|
+
a.last.albums.should == []
|
459
|
+
MODEL_DB.sqls.length.should == 3
|
460
|
+
end
|
461
|
+
|
462
|
+
it "should use the association's block when eager loading by default" do
|
463
|
+
EagerAlbum.eager(:good_tracks).all
|
464
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((tracks.album_id IN (1)) AND (name = 'Good'))"]
|
465
|
+
end
|
466
|
+
|
467
|
+
it "should use the eager_block option when eager loading if given" do
|
468
|
+
EagerBand.eager(:good_albums).all
|
469
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((albums.band_id IN (2)) AND (name = 'good'))"]
|
470
|
+
MODEL_DB.sqls.clear
|
471
|
+
EagerBand.eager(:good_albums=>:good_tracks).all
|
472
|
+
MODEL_DB.sqls.should == ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((albums.band_id IN (2)) AND (name = 'good'))", "SELECT * FROM tracks WHERE ((tracks.album_id IN (1)) AND (name = 'Good'))"]
|
473
|
+
end
|
474
|
+
|
475
|
+
it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
|
476
|
+
proc{EagerBand.eager(:self_titled_albums).all}.should raise_error(Sequel::Error)
|
477
|
+
proc{EagerBand.eager(:albums_by_name).all}.should raise_error(Sequel::Error)
|
478
|
+
end
|
479
|
+
|
480
|
+
it "should respect the association's :select option" do
|
481
|
+
EagerAlbum.eager(:band_name).all
|
482
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (bands.id IN (2))"]
|
483
|
+
MODEL_DB.sqls.clear
|
484
|
+
EagerAlbum.eager(:track_names).all
|
485
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (tracks.album_id IN (1))"]
|
486
|
+
MODEL_DB.sqls.clear
|
487
|
+
EagerAlbum.eager(:genre_names).all
|
488
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT id, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should respect the association's :primary_key option" do
|
492
|
+
EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>:p_k, :key=>:band_id
|
493
|
+
EagerBand.dataset.extend(Module.new {
|
494
|
+
def fetch_rows(sql)
|
495
|
+
MODEL_DB.sqls << sql
|
496
|
+
yield({:p_k=>2, :id=>1})
|
497
|
+
end
|
498
|
+
})
|
499
|
+
as = EagerAlbum.eager(:special_band).all
|
500
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM bands WHERE (bands.p_k IN (2))"]
|
501
|
+
as.length.should == 1
|
502
|
+
as.first.special_band.should == EagerBand.load(:p_k=>2, :id=>1)
|
503
|
+
MODEL_DB.sqls.clear
|
504
|
+
EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>:band_id, :key=>:album_id
|
505
|
+
EagerTrack.dataset.extend(Module.new {
|
506
|
+
def fetch_rows(sql)
|
507
|
+
MODEL_DB.sqls << sql
|
508
|
+
yield({:album_id=>2, :id=>1})
|
509
|
+
end
|
510
|
+
})
|
511
|
+
as = EagerAlbum.eager(:special_tracks).all
|
512
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (2))"]
|
513
|
+
as.length.should == 1
|
514
|
+
as.first.special_tracks.should == [EagerTrack.load(:album_id=>2, :id=>1)]
|
515
|
+
end
|
516
|
+
|
517
|
+
it "should respect the many_to_one association's composite keys" do
|
518
|
+
EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>[:id, :p_k], :key=>[:band_id, :id]
|
519
|
+
EagerBand.dataset.extend(Module.new {
|
520
|
+
def fetch_rows(sql)
|
521
|
+
MODEL_DB.sqls << sql
|
522
|
+
yield({:p_k=>1, :id=>2})
|
523
|
+
end
|
524
|
+
})
|
525
|
+
as = EagerAlbum.eager(:special_band).all
|
526
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM bands WHERE ((bands.id, bands.p_k) IN ((2, 1)))"]
|
527
|
+
as.length.should == 1
|
528
|
+
as.first.special_band.should == EagerBand.load(:p_k=>1, :id=>2)
|
529
|
+
end
|
530
|
+
|
531
|
+
it "should respect the one_to_many association's composite keys" do
|
532
|
+
EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>[:band_id, :id], :key=>[:id, :album_id]
|
533
|
+
EagerTrack.dataset.extend(Module.new {
|
534
|
+
def fetch_rows(sql)
|
535
|
+
MODEL_DB.sqls << sql
|
536
|
+
yield({:album_id=>1, :id=>2})
|
537
|
+
end
|
538
|
+
})
|
539
|
+
as = EagerAlbum.eager(:special_tracks).all
|
540
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((tracks.id, tracks.album_id) IN ((2, 1)))"]
|
541
|
+
as.length.should == 1
|
542
|
+
as.first.special_tracks.should == [EagerTrack.load(:album_id=>1, :id=>2)]
|
543
|
+
end
|
544
|
+
|
545
|
+
it "should respect many_to_many association's composite keys" do
|
546
|
+
EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :left_primary_key=>[:band_id, :id], :left_key=>[:l1, :l2], :right_primary_key=>[:xxx, :id], :right_key=>[:r1, :r2], :join_table=>:ag
|
547
|
+
EagerGenre.dataset.extend(Module.new {
|
548
|
+
def fetch_rows(sql)
|
549
|
+
MODEL_DB.sqls << sql
|
550
|
+
yield({:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>5})
|
551
|
+
yield({:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>6})
|
552
|
+
end
|
553
|
+
})
|
554
|
+
as = EagerAlbum.eager(:special_genres).all
|
555
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ag.l1 AS x_foreign_key_0_x, ag.l2 AS x_foreign_key_1_x FROM genres INNER JOIN ag ON ((ag.r1 = genres.xxx) AND (ag.r2 = genres.id) AND ((ag.l1, ag.l2) IN ((2, 1))))"]
|
556
|
+
as.length.should == 1
|
557
|
+
as.first.special_genres.should == [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
|
558
|
+
end
|
559
|
+
|
560
|
+
it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
|
561
|
+
EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_primary_key=>:xxx, :right_key=>:genre_id, :join_table=>:ag
|
562
|
+
EagerGenre.dataset.extend(Module.new {
|
563
|
+
def fetch_rows(sql)
|
564
|
+
MODEL_DB.sqls << sql
|
565
|
+
yield({:x_foreign_key_x=>2, :id=>5})
|
566
|
+
yield({:x_foreign_key_x=>2, :id=>6})
|
567
|
+
end
|
568
|
+
})
|
569
|
+
as = EagerAlbum.eager(:special_genres).all
|
570
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.xxx) AND (ag.album_id IN (2)))"]
|
571
|
+
as.length.should == 1
|
572
|
+
as.first.special_genres.should == [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
|
573
|
+
end
|
574
|
+
|
575
|
+
it "should use the :eager_loader association option when eager loading" do
|
576
|
+
EagerAlbum.many_to_one :special_band, :eager_loader=>(proc do |key_hash, records, assocs|
|
577
|
+
item = EagerBand.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).order(:name).first
|
578
|
+
records.each{|r| r.associations[:special_band] = item}
|
579
|
+
end)
|
580
|
+
EagerAlbum.one_to_many :special_tracks, :eager_loader=>(proc do |key_hash, records, assocs|
|
581
|
+
items = EagerTrack.filter(:album_id=>records.collect{|r| [r.pk, r.pk*2]}.flatten).all
|
582
|
+
records.each{|r| r.associations[:special_tracks] = items}
|
583
|
+
end)
|
584
|
+
EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :eager_loader=>(proc do |key_hash, records, assocs|
|
585
|
+
items = EagerGenre.inner_join(:ag, [:genre_id]).filter(:album_id=>records.collect{|r| r.pk}).all
|
586
|
+
records.each{|r| r.associations[:special_genres] = items}
|
587
|
+
end)
|
588
|
+
a = EagerAlbum.eager(:special_genres, :special_tracks, :special_band).all
|
589
|
+
a.should be_a_kind_of(Array)
|
590
|
+
a.size.should == 1
|
591
|
+
a.first.should be_a_kind_of(EagerAlbum)
|
592
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
593
|
+
MODEL_DB.sqls.length.should == 4
|
594
|
+
MODEL_DB.sqls[0].should == 'SELECT * FROM albums'
|
595
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM bands WHERE (album_id IN (1, 2)) ORDER BY name LIMIT 1'))
|
596
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM tracks WHERE (album_id IN (1, 2))'))
|
597
|
+
MODEL_DB.sqls[1..-1].should(include('SELECT * FROM genres INNER JOIN ag USING (genre_id) WHERE (album_id IN (1))'))
|
598
|
+
a = a.first
|
599
|
+
a.special_band.should be_a_kind_of(EagerBand)
|
600
|
+
a.special_band.values.should == {:id => 2}
|
601
|
+
a.special_tracks.should be_a_kind_of(Array)
|
602
|
+
a.special_tracks.size.should == 1
|
603
|
+
a.special_tracks.first.should be_a_kind_of(EagerTrack)
|
604
|
+
a.special_tracks.first.values.should == {:id => 3, :album_id=>1}
|
605
|
+
a.special_genres.should be_a_kind_of(Array)
|
606
|
+
a.special_genres.size.should == 1
|
607
|
+
a.special_genres.first.should be_a_kind_of(EagerGenre)
|
608
|
+
a.special_genres.first.values.should == {:id => 4}
|
609
|
+
MODEL_DB.sqls.length.should == 4
|
610
|
+
end
|
611
|
+
|
612
|
+
it "should respect :after_load callbacks on associations when eager loading" do
|
613
|
+
EagerAlbum.many_to_one :al_band, :class=>'EagerBand', :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
|
614
|
+
EagerAlbum.one_to_many :al_tracks, :class=>'EagerTrack', :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
|
615
|
+
EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
|
616
|
+
a = EagerAlbum.eager(:al_band, :al_tracks, :al_genres).all.first
|
617
|
+
a.should == EagerAlbum.load(:id => 1, :band_id => 2)
|
618
|
+
a.al_band.should == EagerBand.load(:id=>4)
|
619
|
+
a.al_tracks.should == [EagerTrack.load(:id=>6, :album_id=>1)]
|
620
|
+
a.al_genres.should == [EagerGenre.load(:id=>8)]
|
621
|
+
end
|
622
|
+
|
623
|
+
it "should respect :uniq option when eagerly loading many_to_many associations" do
|
624
|
+
EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :uniq=>true
|
625
|
+
EagerGenre.dataset.extend(Module.new {
|
626
|
+
def fetch_rows(sql)
|
627
|
+
MODEL_DB.sqls << sql
|
628
|
+
yield({:x_foreign_key_x=>1, :id=>8})
|
629
|
+
yield({:x_foreign_key_x=>1, :id=>8})
|
630
|
+
end
|
631
|
+
})
|
632
|
+
a = EagerAlbum.eager(:al_genres).all.first
|
633
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
634
|
+
a.should == EagerAlbum.load(:id => 1, :band_id => 2)
|
635
|
+
a.al_genres.should == [EagerGenre.load(:id=>8)]
|
636
|
+
end
|
637
|
+
|
638
|
+
it "should respect :distinct option when eagerly loading many_to_many associations" do
|
639
|
+
EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :distinct=>true
|
640
|
+
a = EagerAlbum.eager(:al_genres).all.first
|
641
|
+
MODEL_DB.sqls.should == ['SELECT * FROM albums', "SELECT DISTINCT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
642
|
+
a.should == EagerAlbum.load(:id => 1, :band_id => 2)
|
643
|
+
a.al_genres.should == [EagerGenre.load(:id=>4)]
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
describe Sequel::Model, "#eager_graph" do
|
648
|
+
after(:all) do
|
649
|
+
class ::MockDataset
|
650
|
+
alias clone orig_clone
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
before(:all) do
|
655
|
+
class ::MockDataset
|
656
|
+
alias orig_clone clone
|
657
|
+
def clone(opts = {})
|
658
|
+
c = super()
|
659
|
+
c.opts = @opts.merge(opts)
|
660
|
+
c.instance_variable_set(:@columns, (@columns.dup if @columns))
|
661
|
+
c
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
class ::GraphAlbum < Sequel::Model(:albums)
|
666
|
+
dataset.opts[:from] = [:albums]
|
667
|
+
columns :id, :band_id
|
668
|
+
many_to_one :band, :class=>'GraphBand', :key=>:band_id
|
669
|
+
one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
|
670
|
+
many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
671
|
+
many_to_one :previous_album, :class=>'GraphAlbum'
|
672
|
+
end
|
673
|
+
|
674
|
+
class ::GraphBand < Sequel::Model(:bands)
|
675
|
+
dataset.opts[:from] = [:bands]
|
676
|
+
columns :id, :vocalist_id
|
677
|
+
many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
|
678
|
+
one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id
|
679
|
+
many_to_many :members, :class=>'GraphBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
|
680
|
+
many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
|
681
|
+
end
|
682
|
+
|
683
|
+
class ::GraphTrack < Sequel::Model(:tracks)
|
684
|
+
dataset.opts[:from] = [:tracks]
|
685
|
+
columns :id, :album_id
|
686
|
+
many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
|
687
|
+
end
|
688
|
+
|
689
|
+
class ::GraphGenre < Sequel::Model(:genres)
|
690
|
+
dataset.opts[:from] = [:genres]
|
691
|
+
columns :id
|
692
|
+
many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
|
693
|
+
end
|
694
|
+
|
695
|
+
class ::GraphBandMember < Sequel::Model(:members)
|
696
|
+
dataset.opts[:from] = [:members]
|
697
|
+
columns :id
|
698
|
+
many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
it "should raise an error if called without a symbol or hash" do
|
703
|
+
proc{GraphAlbum.eager_graph(Object.new)}.should raise_error(Sequel::Error)
|
704
|
+
end
|
705
|
+
|
706
|
+
it "should not split results and assign associations if ungraphed is called" do
|
707
|
+
ds = GraphAlbum.eager_graph(:band).ungraphed
|
708
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
709
|
+
def ds.fetch_rows(sql, &block)
|
710
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3})
|
711
|
+
end
|
712
|
+
ds.all.should == [GraphAlbum.load(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3)]
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should eagerly load a single many_to_one association" do
|
716
|
+
ds = GraphAlbum.eager_graph(:band)
|
717
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
718
|
+
def ds.fetch_rows(sql, &block)
|
719
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3})
|
720
|
+
end
|
721
|
+
a = ds.all
|
722
|
+
a.should be_a_kind_of(Array)
|
723
|
+
a.size.should == 1
|
724
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
725
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
726
|
+
a = a.first
|
727
|
+
a.band.should be_a_kind_of(GraphBand)
|
728
|
+
a.band.values.should == {:id => 2, :vocalist_id=>3}
|
729
|
+
end
|
730
|
+
|
731
|
+
it "should eagerly load a single one_to_one association" do
|
732
|
+
GraphAlbum.one_to_one :track, :class=>'GraphTrack', :key=>:album_id
|
733
|
+
ds = GraphAlbum.eager_graph(:track)
|
734
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, track.id AS track_id, track.album_id FROM albums LEFT OUTER JOIN tracks AS track ON (track.album_id = albums.id)'
|
735
|
+
def ds.fetch_rows(sql, &block)
|
736
|
+
yield({:id=>1, :band_id=>2, :track_id=>3, :album_id=>1})
|
737
|
+
end
|
738
|
+
a = ds.all
|
739
|
+
a.should == [GraphAlbum.load(:id => 1, :band_id => 2)]
|
740
|
+
a.first.track.should == GraphTrack.load(:id => 3, :album_id=>1)
|
741
|
+
end
|
742
|
+
|
743
|
+
it "should eagerly load a single one_to_many association" do
|
744
|
+
ds = GraphAlbum.eager_graph(:tracks)
|
745
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
|
746
|
+
def ds.fetch_rows(sql, &block)
|
747
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
748
|
+
end
|
749
|
+
a = ds.all
|
750
|
+
a.should be_a_kind_of(Array)
|
751
|
+
a.size.should == 1
|
752
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
753
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
754
|
+
a = a.first
|
755
|
+
a.tracks.should be_a_kind_of(Array)
|
756
|
+
a.tracks.size.should == 1
|
757
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
758
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
759
|
+
end
|
760
|
+
|
761
|
+
it "should eagerly load a single many_to_many association" do
|
762
|
+
ds = GraphAlbum.eager_graph(:genres)
|
763
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id)'
|
764
|
+
def ds.fetch_rows(sql, &block)
|
765
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4})
|
766
|
+
end
|
767
|
+
a = ds.all
|
768
|
+
a.should be_a_kind_of(Array)
|
769
|
+
a.size.should == 1
|
770
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
771
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
772
|
+
a = a.first
|
773
|
+
a.genres.should be_a_kind_of(Array)
|
774
|
+
a.genres.size.should == 1
|
775
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
776
|
+
a.genres.first.values.should == {:id => 4}
|
777
|
+
end
|
778
|
+
|
779
|
+
it "should eagerly load multiple associations in a single call" do
|
780
|
+
ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
|
781
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
782
|
+
def ds.fetch_rows(sql, &block)
|
783
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6})
|
784
|
+
end
|
785
|
+
a = ds.all
|
786
|
+
a.should be_a_kind_of(Array)
|
787
|
+
a.size.should == 1
|
788
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
789
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
790
|
+
a = a.first
|
791
|
+
a.band.should be_a_kind_of(GraphBand)
|
792
|
+
a.band.values.should == {:id => 2, :vocalist_id=>6}
|
793
|
+
a.tracks.should be_a_kind_of(Array)
|
794
|
+
a.tracks.size.should == 1
|
795
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
796
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
797
|
+
a.genres.should be_a_kind_of(Array)
|
798
|
+
a.genres.size.should == 1
|
799
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
800
|
+
a.genres.first.values.should == {:id => 4}
|
801
|
+
end
|
802
|
+
|
803
|
+
it "should eagerly load multiple associations in separate calls" do
|
804
|
+
ds = GraphAlbum.eager_graph(:genres).eager_graph(:tracks).eager_graph(:band)
|
805
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
806
|
+
def ds.fetch_rows(sql, &block)
|
807
|
+
yield({:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6})
|
808
|
+
end
|
809
|
+
a = ds.all
|
810
|
+
a.should be_a_kind_of(Array)
|
811
|
+
a.size.should == 1
|
812
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
813
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
814
|
+
a = a.first
|
815
|
+
a.band.should be_a_kind_of(GraphBand)
|
816
|
+
a.band.values.should == {:id => 2, :vocalist_id=>6}
|
817
|
+
a.tracks.should be_a_kind_of(Array)
|
818
|
+
a.tracks.size.should == 1
|
819
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
820
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
821
|
+
a.genres.should be_a_kind_of(Array)
|
822
|
+
a.genres.size.should == 1
|
823
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
824
|
+
a.genres.first.values.should == {:id => 4}
|
825
|
+
end
|
826
|
+
|
827
|
+
it "should allow cascading of eager loading for associations of associated models" do
|
828
|
+
ds = GraphTrack.eager_graph(:album=>{:band=>:members})
|
829
|
+
ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
830
|
+
def ds.fetch_rows(sql, &block)
|
831
|
+
yield({:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6})
|
832
|
+
end
|
833
|
+
a = ds.all
|
834
|
+
a.should be_a_kind_of(Array)
|
835
|
+
a.size.should == 1
|
836
|
+
a.first.should be_a_kind_of(GraphTrack)
|
837
|
+
a.first.values.should == {:id => 3, :album_id => 1}
|
838
|
+
a = a.first
|
839
|
+
a.album.should be_a_kind_of(GraphAlbum)
|
840
|
+
a.album.values.should == {:id => 1, :band_id => 2}
|
841
|
+
a.album.band.should be_a_kind_of(GraphBand)
|
842
|
+
a.album.band.values.should == {:id => 2, :vocalist_id=>6}
|
843
|
+
a.album.band.members.should be_a_kind_of(Array)
|
844
|
+
a.album.band.members.size.should == 1
|
845
|
+
a.album.band.members.first.should be_a_kind_of(GraphBandMember)
|
846
|
+
a.album.band.members.first.values.should == {:id => 5}
|
847
|
+
end
|
848
|
+
|
849
|
+
it "should allow cascading of eager loading for multiple *_to_many associations, eliminating duplicates caused by cartesian products" do
|
850
|
+
ds = GraphBand.eager_graph({:albums=>:tracks}, :members)
|
851
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, albums.id AS albums_id, albums.band_id, tracks.id AS tracks_id, tracks.album_id, members.id AS members_id FROM bands LEFT OUTER JOIN albums ON (albums.band_id = bands.id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
852
|
+
def ds.fetch_rows(sql, &block)
|
853
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>5})
|
854
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>6})
|
855
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>5})
|
856
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>6})
|
857
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>5})
|
858
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>6})
|
859
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>5})
|
860
|
+
yield({:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>6})
|
861
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>5})
|
862
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>6})
|
863
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>5})
|
864
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>6})
|
865
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>5})
|
866
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>6})
|
867
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>5})
|
868
|
+
yield({:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>6})
|
869
|
+
end
|
870
|
+
a = ds.all
|
871
|
+
a.should == [GraphBand.load(:id=>1, :vocalist_id=>2), GraphBand.load(:id=>2, :vocalist_id=>2)]
|
872
|
+
members = a.map{|x| x.members}
|
873
|
+
members.should == [[GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)], [GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)]]
|
874
|
+
albums = a.map{|x| x.albums}
|
875
|
+
albums.should == [[GraphAlbum.load(:id=>3, :band_id=>1), GraphAlbum.load(:id=>4, :band_id=>1)], [GraphAlbum.load(:id=>5, :band_id=>2), GraphAlbum.load(:id=>6, :band_id=>2)]]
|
876
|
+
tracks = albums.map{|x| x.map{|y| y.tracks}}
|
877
|
+
tracks.should == [[[GraphTrack.load(:id=>4, :album_id=>3), GraphTrack.load(:id=>5, :album_id=>3)], [GraphTrack.load(:id=>6, :album_id=>4), GraphTrack.load(:id=>7, :album_id=>4)]], [[GraphTrack.load(:id=>8, :album_id=>5), GraphTrack.load(:id=>9, :album_id=>5)], [GraphTrack.load(:id=>1, :album_id=>6), GraphTrack.load(:id=>2, :album_id=>6)]]]
|
878
|
+
end
|
879
|
+
|
880
|
+
it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
|
881
|
+
MODEL_DB.reset
|
882
|
+
ds = GraphAlbum.eager_graph(:tracks)
|
883
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
|
884
|
+
def ds.fetch_rows(sql, &block)
|
885
|
+
@db << sql
|
886
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
887
|
+
end
|
888
|
+
a = ds.all
|
889
|
+
a.should be_a_kind_of(Array)
|
890
|
+
a.size.should == 1
|
891
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
892
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
893
|
+
a = a.first
|
894
|
+
a.tracks.should be_a_kind_of(Array)
|
895
|
+
a.tracks.size.should == 1
|
896
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
897
|
+
a.tracks.first.values.should == {:id => 3, :album_id=>1}
|
898
|
+
a.tracks.first.album.should be_a_kind_of(GraphAlbum)
|
899
|
+
a.tracks.first.album.should == a
|
900
|
+
MODEL_DB.sqls.length.should == 1
|
901
|
+
end
|
902
|
+
|
903
|
+
it "should eager load multiple associations from the same table" do
|
904
|
+
ds = GraphBand.eager_graph(:vocalist, :members)
|
905
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, vocalist.id AS vocalist_id_0, members.id AS members_id FROM bands LEFT OUTER JOIN members AS vocalist ON (vocalist.id = bands.vocalist_id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
906
|
+
def ds.fetch_rows(sql, &block)
|
907
|
+
yield({:id=>2, :vocalist_id=>6, :vocalist_id_0=>6, :members_id=>5})
|
908
|
+
end
|
909
|
+
a = ds.all
|
910
|
+
a.should be_a_kind_of(Array)
|
911
|
+
a.size.should == 1
|
912
|
+
a.first.should be_a_kind_of(GraphBand)
|
913
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
914
|
+
a = a.first
|
915
|
+
a.vocalist.should be_a_kind_of(GraphBandMember)
|
916
|
+
a.vocalist.values.should == {:id => 6}
|
917
|
+
a.members.should be_a_kind_of(Array)
|
918
|
+
a.members.size.should == 1
|
919
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
920
|
+
a.members.first.values.should == {:id => 5}
|
921
|
+
end
|
922
|
+
|
923
|
+
it "should give you a graph of tables when called without .all" do
|
924
|
+
ds = GraphAlbum.eager_graph(:band)
|
925
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
926
|
+
def ds.fetch_rows(sql, &block)
|
927
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3})
|
928
|
+
end
|
929
|
+
ds.first.should == {:albums=>GraphAlbum.load(:id => 1, :band_id => 2), :band=>GraphBand.load(:id => 2, :vocalist_id=>3)}
|
930
|
+
end
|
931
|
+
|
932
|
+
it "should not drop any associated objects if the graph could not be a cartesian product" do
|
933
|
+
ds = GraphBand.eager_graph(:members, :vocalist)
|
934
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, vocalist.id AS vocalist_id_0 FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN members AS vocalist ON (vocalist.id = bands.vocalist_id)'
|
935
|
+
def ds.fetch_rows(sql, &block)
|
936
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6})
|
937
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6})
|
938
|
+
end
|
939
|
+
a = ds.all
|
940
|
+
a.should be_a_kind_of(Array)
|
941
|
+
a.size.should == 1
|
942
|
+
a.first.should be_a_kind_of(GraphBand)
|
943
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
944
|
+
a = a.first
|
945
|
+
a.vocalist.should be_a_kind_of(GraphBandMember)
|
946
|
+
a.vocalist.values.should == {:id => 6}
|
947
|
+
a.members.should be_a_kind_of(Array)
|
948
|
+
a.members.size.should == 2
|
949
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
950
|
+
a.members.first.values.should == {:id => 5}
|
951
|
+
a.members.last.should be_a_kind_of(GraphBandMember)
|
952
|
+
a.members.last.values.should == {:id => 5}
|
953
|
+
end
|
954
|
+
|
955
|
+
it "should respect the :cartesian_product_number option" do
|
956
|
+
GraphBand.many_to_one :other_vocalist, :class=>'GraphBandMember', :key=>:vocalist_id, :cartesian_product_number=>1
|
957
|
+
ds = GraphBand.eager_graph(:members, :other_vocalist)
|
958
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, other_vocalist.id AS other_vocalist_id FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN members AS other_vocalist ON (other_vocalist.id = bands.vocalist_id)'
|
959
|
+
def ds.fetch_rows(sql, &block)
|
960
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :other_vocalist_id=>6})
|
961
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :other_vocalist_id=>6})
|
962
|
+
end
|
963
|
+
a = ds.all
|
964
|
+
a.should == [GraphBand.load(:id=>2, :vocalist_id => 6)]
|
965
|
+
a.first.other_vocalist.should == GraphBandMember.load(:id=>6)
|
966
|
+
a.first.members.should == [GraphBandMember.load(:id=>5)]
|
967
|
+
end
|
968
|
+
|
969
|
+
it "should drop duplicate items that occur in sequence if the graph could be a cartesian product" do
|
970
|
+
ds = GraphBand.eager_graph(:members, :genres)
|
971
|
+
ds.sql.should == 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, genres.id AS genres_id FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN bg ON (bg.band_id = bands.id) LEFT OUTER JOIN genres ON (genres.id = bg.genre_id)'
|
972
|
+
def ds.fetch_rows(sql, &block)
|
973
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>7})
|
974
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>8})
|
975
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>7})
|
976
|
+
yield({:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>8})
|
977
|
+
end
|
978
|
+
a = ds.all
|
979
|
+
a.should be_a_kind_of(Array)
|
980
|
+
a.size.should == 1
|
981
|
+
a.first.should be_a_kind_of(GraphBand)
|
982
|
+
a.first.values.should == {:id => 2, :vocalist_id => 6}
|
983
|
+
a = a.first
|
984
|
+
a.members.should be_a_kind_of(Array)
|
985
|
+
a.members.size.should == 2
|
986
|
+
a.members.first.should be_a_kind_of(GraphBandMember)
|
987
|
+
a.members.first.values.should == {:id => 5}
|
988
|
+
a.members.last.should be_a_kind_of(GraphBandMember)
|
989
|
+
a.members.last.values.should == {:id => 6}
|
990
|
+
a.genres.size.should == 2
|
991
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
992
|
+
a.genres.first.values.should == {:id => 7}
|
993
|
+
a.genres.last.should be_a_kind_of(GraphGenre)
|
994
|
+
a.genres.last.values.should == {:id => 8}
|
995
|
+
end
|
996
|
+
|
997
|
+
it "should be able to be used in combination with #eager" do
|
998
|
+
MODEL_DB.reset
|
999
|
+
ds = GraphAlbum.eager_graph(:tracks).eager(:genres)
|
1000
|
+
def ds.fetch_rows(sql, &block)
|
1001
|
+
@db << sql
|
1002
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
|
1003
|
+
end
|
1004
|
+
ds2 = GraphGenre.dataset
|
1005
|
+
def ds2.fetch_rows(sql, &block)
|
1006
|
+
@db << sql
|
1007
|
+
yield({:id=>6, :x_foreign_key_x=>1})
|
1008
|
+
end
|
1009
|
+
a = ds.all
|
1010
|
+
a.should be_a_kind_of(Array)
|
1011
|
+
a.size.should == 1
|
1012
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
1013
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
1014
|
+
a = a.first
|
1015
|
+
a.tracks.should be_a_kind_of(Array)
|
1016
|
+
a.tracks.size.should == 1
|
1017
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
1018
|
+
a.tracks.first.values.should == {:id=>3, :album_id=>1}
|
1019
|
+
a.genres.should be_a_kind_of(Array)
|
1020
|
+
a.genres.size.should == 1
|
1021
|
+
a.genres.first.should be_a_kind_of(GraphGenre)
|
1022
|
+
a.genres.first.values.should == {:id=>6}
|
1023
|
+
MODEL_DB.sqls.should == ['SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)',
|
1024
|
+
"SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON ((ag.genre_id = genres.id) AND (ag.album_id IN (1)))"]
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
it "should handle no associated records for a single many_to_one association" do
|
1028
|
+
ds = GraphAlbum.eager_graph(:band)
|
1029
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
1030
|
+
def ds.fetch_rows(sql, &block)
|
1031
|
+
yield({:id=>1, :band_id=>2, :band_id_0=>nil, :vocalist_id=>nil})
|
1032
|
+
end
|
1033
|
+
a = ds.all
|
1034
|
+
a.should be_a_kind_of(Array)
|
1035
|
+
a.size.should == 1
|
1036
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
1037
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
1038
|
+
a.first.associations.fetch(:band, 2).should == nil
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
it "should handle no associated records for a single one_to_many association" do
|
1042
|
+
ds = GraphAlbum.eager_graph(:tracks)
|
1043
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
|
1044
|
+
def ds.fetch_rows(sql, &block)
|
1045
|
+
yield({:id=>1, :band_id=>2, :tracks_id=>nil, :album_id=>nil})
|
1046
|
+
end
|
1047
|
+
a = ds.all
|
1048
|
+
a.should be_a_kind_of(Array)
|
1049
|
+
a.size.should == 1
|
1050
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
1051
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
1052
|
+
a.first.tracks.should == []
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
it "should handle no associated records for a single many_to_many association" do
|
1056
|
+
ds = GraphAlbum.eager_graph(:genres)
|
1057
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id)'
|
1058
|
+
def ds.fetch_rows(sql, &block)
|
1059
|
+
yield({:id=>1, :band_id=>2, :genres_id=>nil})
|
1060
|
+
end
|
1061
|
+
a = ds.all
|
1062
|
+
a.should be_a_kind_of(Array)
|
1063
|
+
a.size.should == 1
|
1064
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
1065
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
1066
|
+
a.first.genres.should == []
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
it "should handle missing associated records when loading multiple associations" do
|
1070
|
+
ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
|
1071
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
|
1072
|
+
def ds.fetch_rows(sql, &block)
|
1073
|
+
yield({:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>3, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil})
|
1074
|
+
yield({:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>4, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil})
|
1075
|
+
yield({:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>5, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil})
|
1076
|
+
yield({:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>6, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil})
|
1077
|
+
end
|
1078
|
+
a = ds.all
|
1079
|
+
a.should be_a_kind_of(Array)
|
1080
|
+
a.size.should == 1
|
1081
|
+
a.first.should be_a_kind_of(GraphAlbum)
|
1082
|
+
a.first.values.should == {:id => 1, :band_id => 2}
|
1083
|
+
a = a.first
|
1084
|
+
a.tracks.should be_a_kind_of(Array)
|
1085
|
+
a.tracks.size.should == 4
|
1086
|
+
a.tracks.first.should be_a_kind_of(GraphTrack)
|
1087
|
+
a.tracks.collect{|x|x[:id]}.should == [3,4,5,6]
|
1088
|
+
a.associations.fetch(:band, 2).should == nil
|
1089
|
+
a.genres.should == []
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
it "should handle missing associated records when cascading eager loading for associations of associated models" do
|
1093
|
+
ds = GraphTrack.eager_graph(:album=>{:band=>:members})
|
1094
|
+
ds.sql.should == 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
|
1095
|
+
def ds.fetch_rows(sql, &block)
|
1096
|
+
yield({:id=>2, :album_id=>2, :album_id_0=>nil, :band_id=>nil, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil})
|
1097
|
+
yield({:id=>3, :album_id=>3, :album_id_0=>3, :band_id=>3, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil})
|
1098
|
+
yield({:id=>4, :album_id=>4, :album_id_0=>4, :band_id=>2, :members_id=>nil, :band_id_0=>2, :vocalist_id=>6})
|
1099
|
+
yield({:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>5, :band_id_0=>4, :vocalist_id=>8})
|
1100
|
+
yield({:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>6, :band_id_0=>4, :vocalist_id=>8})
|
1101
|
+
end
|
1102
|
+
a = ds.all
|
1103
|
+
a.should be_a_kind_of(Array)
|
1104
|
+
a.size.should == 4
|
1105
|
+
a.first.should be_a_kind_of(GraphTrack)
|
1106
|
+
a.collect{|x|x[:id]}.should == [2,3,4,5]
|
1107
|
+
a[0].associations.fetch(:album, 2).should == nil
|
1108
|
+
a[1].album.should be_a_kind_of(GraphAlbum)
|
1109
|
+
a[1].album.values.should == {:id => 3, :band_id => 3}
|
1110
|
+
a[1].album.associations.fetch(:band, 2).should == nil
|
1111
|
+
a[2].album.should be_a_kind_of(GraphAlbum)
|
1112
|
+
a[2].album.values.should == {:id => 4, :band_id => 2}
|
1113
|
+
a[2].album.band.should be_a_kind_of(GraphBand)
|
1114
|
+
a[2].album.band.values.should == {:id => 2, :vocalist_id=>6}
|
1115
|
+
a[2].album.band.members.should == []
|
1116
|
+
a[3].album.should be_a_kind_of(GraphAlbum)
|
1117
|
+
a[3].album.values.should == {:id => 1, :band_id => 4}
|
1118
|
+
a[3].album.band.should be_a_kind_of(GraphBand)
|
1119
|
+
a[3].album.band.values.should == {:id => 4, :vocalist_id=>8}
|
1120
|
+
a[3].album.band.members.size.should == 2
|
1121
|
+
a[3].album.band.members.first.should be_a_kind_of(GraphBandMember)
|
1122
|
+
a[3].album.band.members.first.values.should == {:id => 5}
|
1123
|
+
a[3].album.band.members.last.should be_a_kind_of(GraphBandMember)
|
1124
|
+
a[3].album.band.members.last.values.should == {:id => 6}
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
it "should respect the association's :primary_key option" do
|
1128
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :primary_key=>:vocalist_id
|
1129
|
+
ds = GraphAlbum.eager_graph(:inner_band)
|
1130
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.vocalist_id = albums.band_id)'
|
1131
|
+
def ds.fetch_rows(sql, &block)
|
1132
|
+
yield({:id=>3, :band_id=>2, :inner_band_id=>5, :vocalist_id=>2})
|
1133
|
+
end
|
1134
|
+
as = ds.all
|
1135
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1136
|
+
as.first.inner_band.should == GraphBand.load(:id=>5, :vocalist_id=>2)
|
1137
|
+
|
1138
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :primary_key=>:band_id
|
1139
|
+
ds = GraphAlbum.eager_graph(:right_tracks)
|
1140
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.band_id)'
|
1141
|
+
def ds.fetch_rows(sql, &block)
|
1142
|
+
yield({:id=>3, :band_id=>2, :right_tracks_id=>5, :album_id=>2})
|
1143
|
+
yield({:id=>3, :band_id=>2, :right_tracks_id=>6, :album_id=>2})
|
1144
|
+
end
|
1145
|
+
as = ds.all
|
1146
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1147
|
+
as.first.right_tracks.should == [GraphTrack.load(:id=>5, :album_id=>2), GraphTrack.load(:id=>6, :album_id=>2)]
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
it "should respect many_to_one association's composite keys" do
|
1151
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>[:band_id, :id], :primary_key=>[:vocalist_id, :id]
|
1152
|
+
ds = GraphAlbum.eager_graph(:inner_band)
|
1153
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON ((inner_band.vocalist_id = albums.band_id) AND (inner_band.id = albums.id))'
|
1154
|
+
def ds.fetch_rows(sql, &block)
|
1155
|
+
yield({:id=>3, :band_id=>2, :inner_band_id=>3, :vocalist_id=>2})
|
1156
|
+
end
|
1157
|
+
as = ds.all
|
1158
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1159
|
+
as.first.inner_band.should == GraphBand.load(:id=>3, :vocalist_id=>2)
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
it "should respect one_to_many association's composite keys" do
|
1163
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>[:album_id, :id], :primary_key=>[:band_id, :id]
|
1164
|
+
ds = GraphAlbum.eager_graph(:right_tracks)
|
1165
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.band_id) AND (right_tracks.id = albums.id))'
|
1166
|
+
def ds.fetch_rows(sql, &block)
|
1167
|
+
yield({:id=>3, :band_id=>2, :right_tracks_id=>3, :album_id=>2})
|
1168
|
+
end
|
1169
|
+
as = ds.all
|
1170
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1171
|
+
as.first.right_tracks.should == [GraphTrack.load(:id=>3, :album_id=>2)]
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
it "should respect many_to_many association's composite keys" do
|
1175
|
+
GraphAlbum.many_to_many :sbands, :class=>'GraphBand', :left_key=>[:l1, :l2], :left_primary_key=>[:band_id, :id], :right_key=>[:r1, :r2], :right_primary_key=>[:vocalist_id, :id], :join_table=>:b
|
1176
|
+
ds = GraphAlbum.eager_graph(:sbands)
|
1177
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, sbands.id AS sbands_id, sbands.vocalist_id FROM albums LEFT OUTER JOIN b ON ((b.l1 = albums.band_id) AND (b.l2 = albums.id)) LEFT OUTER JOIN bands AS sbands ON ((sbands.vocalist_id = b.r1) AND (sbands.id = b.r2))'
|
1178
|
+
def ds.fetch_rows(sql, &block)
|
1179
|
+
yield({:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6})
|
1180
|
+
yield({:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22})
|
1181
|
+
end
|
1182
|
+
as = ds.all
|
1183
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1184
|
+
as.first.sbands.should == [GraphBand.load(:id=>5, :vocalist_id=>6), GraphBand.load(:id=>6, :vocalist_id=>22)]
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
|
1188
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :left_primary_key=>:band_id, :right_key=>:genre_id, :right_primary_key=>:xxx, :join_table=>:ag
|
1189
|
+
ds = GraphAlbum.eager_graph(:inner_genres)
|
1190
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.band_id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.xxx = ag.genre_id)'
|
1191
|
+
def ds.fetch_rows(sql, &block)
|
1192
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12})
|
1193
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22})
|
1194
|
+
end
|
1195
|
+
as = ds.all
|
1196
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1197
|
+
as.first.inner_genres.should == [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
it "should respect the association's :graph_select option" do
|
1201
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_select=>:vocalist_id
|
1202
|
+
GraphAlbum.eager_graph(:inner_band).sql.should == 'SELECT albums.id, albums.band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.id = albums.band_id)'
|
1203
|
+
|
1204
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_select=>[:album_id]
|
1205
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
|
1206
|
+
|
1207
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_select=>[]
|
1208
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
it "should respect the association's :graph_join_type option" do
|
1212
|
+
GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_join_type=>:inner
|
1213
|
+
GraphAlbum.eager_graph(:inner_band).sql.should == 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums INNER JOIN bands AS inner_band ON (inner_band.id = albums.band_id)'
|
1214
|
+
|
1215
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_join_type=>:right_outer
|
1216
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums RIGHT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
|
1217
|
+
|
1218
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_type=>:inner
|
1219
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
it "should respect the association's :graph_join_table_join_type option" do
|
1223
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner
|
1224
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
1225
|
+
|
1226
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner, :graph_join_type=>:right_outer
|
1227
|
+
GraphAlbum.eager_graph(:inner_genres).sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) RIGHT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
it "should respect the association's :conditions option" do
|
1231
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :conditions=>{:active=>true}
|
1232
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
|
1233
|
+
|
1234
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :conditions=>{:id=>(0..100)}
|
1235
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
|
1236
|
+
|
1237
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :conditions=>{true=>:active}
|
1238
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
it "should respect the association's :graph_conditions option" do
|
1242
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
|
1243
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
|
1244
|
+
|
1245
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:id=>(0..100)}
|
1246
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
|
1247
|
+
|
1248
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
|
1249
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
it "should respect the association's :graph_join_table_conditions option" do
|
1253
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_conditions=>{:active=>true}
|
1254
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND (ag.active IS TRUE)) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
|
1255
|
+
|
1256
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}, :graph_join_table_conditions=>{true=>:active}
|
1257
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
it "should respect the association's :graph_block option" do
|
1261
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}
|
1262
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
|
1263
|
+
|
1264
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_block=>proc{|ja,lja,js| {:id.qualify(ja)=>(0..100)}}
|
1265
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
|
1266
|
+
|
1267
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}
|
1268
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
it "should respect the association's :graph_join_block option" do
|
1272
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_block=>proc{|ja,lja,js| {:active.qualify(ja)=>true}}
|
1273
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND (ag.active IS TRUE)) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
|
1274
|
+
|
1275
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}, :graph_join_table_block=>proc{|ja,lja,js| {true=>:active.qualify(lja)}}
|
1276
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
it "should respect the association's :eager_grapher option" do
|
1280
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :eager_grapher=>proc{|ds, aa, ta| ds.graph(GraphBand, {:active=>true}, :table_alias=>aa, :join_type=>:inner)}
|
1281
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums INNER JOIN bands AS active_band ON (active_band.active IS TRUE)"
|
1282
|
+
|
1283
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :eager_grapher=>proc{|ds, aa, ta| ds.graph(GraphTrack, nil, :join_type=>:natural, :table_alias=>aa)}
|
1284
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
|
1285
|
+
|
1286
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :eager_grapher=>proc{|ds, aa, ta| ds.graph(:ag, {:album_id=>:id}, :table_alias=>:a123, :implicit_qualifier=>ta).graph(GraphGenre, [:album_id], :table_alias=>aa)}
|
1287
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag AS a123 ON (a123.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
it "should respect the association's :graph_only_conditions option" do
|
1291
|
+
GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
|
1292
|
+
GraphAlbum.eager_graph(:active_band).sql.should == "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON (active_band.active IS TRUE)"
|
1293
|
+
|
1294
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_only_conditions=>nil, :graph_join_type=>:natural
|
1295
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
|
1296
|
+
|
1297
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>[:album_id]
|
1298
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
it "should respect the association's :graph_join_table_only_conditions option" do
|
1302
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_only_conditions=>{:active=>true}
|
1303
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.active IS TRUE) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
|
1304
|
+
|
1305
|
+
GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>(:price + 2 > 100), :graph_join_table_only_conditions=>"active"
|
1306
|
+
GraphAlbum.eager_graph(:active_genres).sql.should == "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (active) LEFT OUTER JOIN genres AS active_genres ON ((price + 2) > 100)"
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
it "should create unique table aliases for all associations" do
|
1310
|
+
GraphAlbum.eager_graph(:previous_album=>{:previous_album=>:previous_album}).sql.should == "SELECT albums.id, albums.band_id, previous_album.id AS previous_album_id, previous_album.band_id AS previous_album_band_id, previous_album_0.id AS previous_album_0_id, previous_album_0.band_id AS previous_album_0_band_id, previous_album_1.id AS previous_album_1_id, previous_album_1.band_id AS previous_album_1_band_id FROM albums LEFT OUTER JOIN albums AS previous_album ON (previous_album.id = albums.previous_album_id) LEFT OUTER JOIN albums AS previous_album_0 ON (previous_album_0.id = previous_album.previous_album_id) LEFT OUTER JOIN albums AS previous_album_1 ON (previous_album_1.id = previous_album_0.previous_album_id)"
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
it "should respect the association's :order" do
|
1314
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1315
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.id, right_tracks.album_id'
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
|
1319
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:blah__id.identifier, :blah__id.identifier.desc, :blah__id.desc, :blah__id, :album_id, :album_id.desc, 1, 'RANDOM()'.lit, :a.qualify(:b)]
|
1320
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.blah__id, right_tracks.blah__id DESC, blah.id DESC, blah.id, right_tracks.album_id, right_tracks.album_id DESC, 1, RANDOM(), b.a'
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
it "should not respect the association's :order if :order_eager_graph is false" do
|
1324
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id], :order_eager_graph=>false
|
1325
|
+
GraphAlbum.eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
it "should add the association's :order to the existing order" do
|
1329
|
+
GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1330
|
+
GraphAlbum.order(:band_id).eager_graph(:right_tracks).sql.should == 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY band_id, right_tracks.id, right_tracks.album_id'
|
1331
|
+
end
|
1332
|
+
|
1333
|
+
it "should add the association's :order for cascading associations" do
|
1334
|
+
GraphBand.one_to_many :a_albums, :class=>'GraphAlbum', :key=>:band_id, :order=>:name
|
1335
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1336
|
+
GraphBand.eager_graph(:a_albums=>:b_tracks).sql.should == 'SELECT bands.id, bands.vocalist_id, a_albums.id AS a_albums_id, a_albums.band_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM bands LEFT OUTER JOIN albums AS a_albums ON (a_albums.band_id = bands.id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = a_albums.id) ORDER BY a_albums.name, b_tracks.id, b_tracks.album_id'
|
1337
|
+
GraphAlbum.one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id, :order=>[:band_id, :id]
|
1338
|
+
GraphAlbum.eager_graph(:albums=>{:albums=>:albums}).sql.should == 'SELECT albums.id, albums.band_id, albums_0.id AS albums_0_id, albums_0.band_id AS albums_0_band_id, albums_1.id AS albums_1_id, albums_1.band_id AS albums_1_band_id, albums_2.id AS albums_2_id, albums_2.band_id AS albums_2_band_id FROM albums LEFT OUTER JOIN albums AS albums_0 ON (albums_0.band_id = albums.id) LEFT OUTER JOIN albums AS albums_1 ON (albums_1.band_id = albums_0.id) LEFT OUTER JOIN albums AS albums_2 ON (albums_2.band_id = albums_1.id) ORDER BY albums_0.band_id, albums_0.id, albums_1.band_id, albums_1.id, albums_2.band_id, albums_2.id'
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
it "should add the associations :order for multiple associations" do
|
1342
|
+
GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :order=>:id
|
1343
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
|
1344
|
+
GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.should == 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = albums.id) ORDER BY a_genres.id, b_tracks.id, b_tracks.album_id'
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
it "should use the correct qualifier when graphing multiple tables with extra conditions" do
|
1348
|
+
GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
|
1349
|
+
GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:a=>:b}
|
1350
|
+
GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.should == 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON ((b_tracks.album_id = albums.id) AND (b_tracks.a = albums.b))'
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
it "should eagerly load associated records for classes that do not have a primary key" do
|
1354
|
+
GraphAlbum.no_primary_key
|
1355
|
+
GraphGenre.no_primary_key
|
1356
|
+
GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :left_primary_key=>:band_id, :right_key=>:genre_id, :right_primary_key=>:xxx, :join_table=>:ag
|
1357
|
+
ds = GraphAlbum.eager_graph(:inner_genres)
|
1358
|
+
ds.sql.should == 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.band_id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.xxx = ag.genre_id)'
|
1359
|
+
def ds.fetch_rows(sql, &block)
|
1360
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12})
|
1361
|
+
yield({:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22})
|
1362
|
+
end
|
1363
|
+
as = ds.all
|
1364
|
+
as.should == [GraphAlbum.load(:id=>3, :band_id=>2)]
|
1365
|
+
as.first.inner_genres.should == [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
it "should handle eager loading with schemas and aliases of different types" do
|
1369
|
+
GraphAlbum.eager_graph(:band).join(:s__genres, [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1370
|
+
GraphAlbum.eager_graph(:band).join(:genres.qualify(:s), [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1371
|
+
GraphAlbum.eager_graph(:band).join(:s__b.as('genres'), [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1372
|
+
GraphAlbum.eager_graph(:band).join(:s__b, [:b_id], :genres.identifier).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1373
|
+
GraphAlbum.eager_graph(:band).join(:genres.identifier, [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1374
|
+
GraphAlbum.eager_graph(:band).join('genres', [:b_id]).eager_graph(:genres).sql.should == 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
it "should raise errors if invalid aliases or table styles are used" do
|
1378
|
+
proc{GraphAlbum.from_self(:alias=>:bands.qualify(:s)).eager_graph(:band)}.should raise_error(Sequel::Error)
|
1379
|
+
proc{GraphAlbum.from('?'.lit(:bands)).eager_graph(:band)}.should raise_error(Sequel::Error)
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
it "should eagerly load schema qualified tables correctly with joins" do
|
1383
|
+
c1 = Class.new(GraphAlbum)
|
1384
|
+
c2 = Class.new(GraphGenre)
|
1385
|
+
c1.dataset = c1.dataset.from(:s__a)
|
1386
|
+
c2.dataset = c2.dataset.from(:s__g)
|
1387
|
+
c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:s__ag
|
1388
|
+
ds = c1.join(:s__t, [:b_id]).eager_graph(:a_genres)
|
1389
|
+
ds.sql.should == 'SELECT a.id, a_genres.id AS a_genres_id FROM (SELECT * FROM s.a INNER JOIN s.t USING (b_id)) AS a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
|
1390
|
+
end
|
1391
|
+
end
|