diff --git a/lib/active_force/association/association.rb b/lib/active_force/association/association.rb index 8bb1428..0d7cdd5 100644 --- a/lib/active_force/association/association.rb +++ b/lib/active_force/association/association.rb @@ -26,6 +26,14 @@ def relationship_name options[:relationship_name] || relation_model.to_s.constantize.table_name end + def scoped_as + options[:scoped_as] || nil + end + + def scoped? + options[:scoped_as].present? + end + ### # Does this association's relation_model represent # +sfdc_table_name+? Examples of +sfdc_table_name+ diff --git a/lib/active_force/association/eager_load_projection_builder.rb b/lib/active_force/association/eager_load_projection_builder.rb index 4c827cf..70dfe74 100644 --- a/lib/active_force/association/eager_load_projection_builder.rb +++ b/lib/active_force/association/eager_load_projection_builder.rb @@ -1,5 +1,6 @@ module ActiveForce module Association + class InvalidEagerLoadAssociation < StandardError; end class EagerLoadProjectionBuilder class << self def build(association, parent_association_field = nil) @@ -34,6 +35,13 @@ def initialize(association, parent_association_field = nil) def projections raise "Must define #{self.class.name}#projections" end + + def apply_association_scope(query) + return query unless association.scoped? + raise InvalidEagerLoadAssociation, "Cannot use scopes that expect arguments: #{association.relation_name}" if association.scoped_as.arity.positive? + + query.instance_exec(&association.scoped_as) + end end class HasManyAssociationProjectionBuilder < AbstractProjectionBuilder @@ -43,17 +51,17 @@ class HasManyAssociationProjectionBuilder < AbstractProjectionBuilder # to be pluralized def projections relationship_name = association.sfdc_association_field - query = Query.new relationship_name + query = ActiveQuery.new(association.relation_model, relationship_name) query.fields association.relation_model.fields - ["(#{query.to_s})"] + ["(#{apply_association_scope(query).to_s})"] end end class HasOneAssociationProjectionBuilder < AbstractProjectionBuilder def projections - query = Query.new association.sfdc_association_field + query = ActiveQuery.new(association.relation_model, association.sfdc_association_field) query.fields association.relation_model.fields - ["(#{query.to_s})"] + ["(#{apply_association_scope(query).to_s})"] end end diff --git a/spec/active_force/sobject/includes_spec.rb b/spec/active_force/sobject/includes_spec.rb index 21a7a2f..b4ab9c9 100644 --- a/spec/active_force/sobject/includes_spec.rb +++ b/spec/active_force/sobject/includes_spec.rb @@ -225,6 +225,13 @@ module ActiveForce end end + context 'when assocation has a scope' do + it 'formulates the correct SOQL query with the scope applied' do + soql = Post.includes(:impossible_comments).where(id: '1234').to_s + expect(soql).to eq "SELECT Id, Title__c, BlogId, (SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comments__r WHERE (1 = 0)) FROM Post__c WHERE (Id = '1234')" + end + end + context 'with namespaced SObjects' do it 'formulates the correct SOQL query' do soql = Salesforce::Quota.includes(:prez_clubs).where(id: '123').to_s @@ -286,9 +293,26 @@ module ActiveForce end end + context 'has_one' do + context 'when assocation has a scope' do + it 'formulates the correct SOQL query with the scope applied' do + soql = Post.includes(:last_comment).where(id: '1234').to_s + expect(soql).to eq "SELECT Id, Title__c, BlogId, (SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__r WHERE (NOT ((Body__c = NULL))) ORDER BY CreatedDate DESC) FROM Post__c WHERE (Id = '1234')" + end + end + + end + context 'when invalid associations are passed' do - it 'raises an error' do - expect { Quota.includes(:invalid).find('123') }.to raise_error(ActiveForce::Association::InvalidAssociationError, 'Association named invalid was not found on Quota') + context 'when the association is not defined' do + it 'raises an error' do + expect { Quota.includes(:invalid).find('123') }.to raise_error(ActiveForce::Association::InvalidAssociationError, 'Association named invalid was not found on Quota') + end + end + context 'when the association is scoped and accepts an argument' do + it 'raises and error' do + expect { Post.includes(:reply_comments).find('1234')}.to raise_error(ActiveForce::Association::InvalidEagerLoadAssociation) + end end end end