Skip to content

Commit

Permalink
Add the :eager_graph association option, works just like :eager excep…
Browse files Browse the repository at this point in the history
…t it uses #eager_graph

This doesn't work perfectly yet, as the association filters don't use
qualified columns.  That will be fixed in a later commit.
  • Loading branch information
jeremyevans committed Jun 27, 2008
1 parent b686d4a commit 1de4a7b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 1 deletion.
2 changes: 2 additions & 0 deletions sequel/CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD

* Add the :eager_graph association option, works just like :eager except it uses #eager_graph (jeremyevans)

* Make eager loading via #eager respect the :limit association option (jeremyevans)

* Add :graph_join_table_join_type association option (jeremyevans)
Expand Down
8 changes: 7 additions & 1 deletion sequel/lib/sequel_model/associations.rb
Expand Up @@ -87,7 +87,11 @@ def all_association_reflections
# - :class - The associated class or its name. If not
# given, uses the association's name, which is camelized (and
# singularized unless the type is :many_to_one)
# - :eager - The associations to eagerly load when loading the associated object.
# - :eager - The associations to eagerly load via EagerLoading#eager when loading the associated object(s).
# For many_to_one associations, this is ignored unless this association is
# being eagerly loaded, as it doesn't save queries unless multiple objects
# can be loaded at once.
# - :eager_graph - The associations to eagerly load via EagerLoading#eager_graph when loading the associated object(s).
# For many_to_one associations, this is ignored unless this association is
# being eagerly loaded, as it doesn't save queries unless multiple objects
# can be loaded at once.
Expand Down Expand Up @@ -244,6 +248,7 @@ def def_association_dataset_methods(name, opts, &block)
dataset_block = opts[:block]
order = opts[:order]
eager = opts[:eager]
eager_graph = opts[:eager_graph]
limit = opts[:limit]

# If a block is given, define a helper method for it, because it takes
Expand All @@ -260,6 +265,7 @@ def def_association_dataset_methods(name, opts, &block)
ds = ds.order(*order) if order
ds = ds.limit(*limit) if limit
ds = ds.eager(eager) if eager
ds = ds.eager_graph(eager_graph) if eager_graph
ds = send(helper_method, ds) if dataset_block
ds
end
Expand Down
1 change: 1 addition & 0 deletions sequel/lib/sequel_model/eager_loading.rb
Expand Up @@ -371,6 +371,7 @@ def eager_load(a)
assoc_block = Proc.new do |d|
d = d.order(*reflection[:order]) if reflection[:order]
d = d.limit(*reflection[:limit]) if reflection[:limit]
d = d.eager_graph(reflection[:eager_graph]) if reflection[:eager_graph]
d = d.eager(reflection[:eager]) if reflection[:eager]
d = d.eager(eager_assoc[assoc_name]) if eager_assoc[assoc_name]
d = reflection[:eager_block].call(d) if reflection[:eager_block]
Expand Down
61 changes: 61 additions & 0 deletions sequel/spec/eager_loading_spec.rb
Expand Up @@ -20,6 +20,7 @@ class EagerAlbum < Sequel::Model(:albums)
class EagerBand < Sequel::Model(:bands)
columns :id
one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks
one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks
many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
one_to_many :good_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_block=>proc{|ds| ds.filter(:name=>'good')} do |ds|
ds.filter(:name=>'Good')
Expand Down Expand Up @@ -47,6 +48,10 @@ class EagerBandMember < Sequel::Model(:members)
end

EagerAlbum.dataset.extend(Module.new {
def columns
[:id, :band_id]
end

def fetch_rows(sql)
h = if sql =~ /101/
{:id => 101, :band_id=> 101}
Expand Down Expand Up @@ -238,6 +243,62 @@ def fetch_rows(sql)
MODEL_DB.sqls.length.should == 3
end

it "should cascade eagerly loading when the :eager_graph association option is used" do
EagerAlbum.dataset.extend(Module.new {
def fetch_rows(sql)
@db << sql
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
end
})
a = EagerBand.eager(:graph_albums).all
a.should be_a_kind_of(Array)
a.size.should == 1
a.first.should be_a_kind_of(EagerBand)
a.first.values.should == {:id => 2}
MODEL_DB.sqls.should == ['SELECT * FROM bands',
'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 (band_id IN (2))']
a = a.first
a.graph_albums.should be_a_kind_of(Array)
a.graph_albums.size.should == 1
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
a = a.graph_albums.first
a.tracks.should be_a_kind_of(Array)
a.tracks.size.should == 1
a.tracks.first.should be_a_kind_of(EagerTrack)
a.tracks.first.values.should == {:id => 3, :album_id => 1}
MODEL_DB.sqls.length.should == 2
end

it "should respect :eager_graph when lazily loading an association" do
a = EagerBand.all
a.should be_a_kind_of(Array)
a.size.should == 1
a.first.should be_a_kind_of(EagerBand)
a.first.values.should == {:id => 2}
MODEL_DB.sqls.should == ['SELECT * FROM bands']
a = a.first
EagerAlbum.dataset.extend(Module.new {
def fetch_rows(sql)
@db << sql
yield({:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1})
end
})
a.graph_albums
MODEL_DB.sqls.should == ['SELECT * FROM bands',
'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 (band_id = 2)']
a.graph_albums.should be_a_kind_of(Array)
a.graph_albums.size.should == 1
a.graph_albums.first.should be_a_kind_of(EagerAlbum)
a.graph_albums.first.values.should == {:id => 1, :band_id => 2}
a = a.graph_albums.first
a.tracks.should be_a_kind_of(Array)
a.tracks.size.should == 1
a.tracks.first.should be_a_kind_of(EagerTrack)
a.tracks.first.values.should == {:id => 3, :album_id => 1}
MODEL_DB.sqls.length.should == 2
end

it "should respect :order when eagerly loading" do
a = EagerBandMember.eager(:bands).all
a.should be_a_kind_of(Array)
Expand Down

0 comments on commit 1de4a7b

Please sign in to comment.