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