# frozen_string_literal: truemoduleActiveRecordmoduleAssociationsclassAssociationScope#:nodoc:defself.scope(association)INSTANCE.scope(association)enddefself.create(&block)block||=lambda{|val|val}new(block)enddefinitialize(value_transformation)@value_transformation=value_transformationendINSTANCE=createdefscope(association)klass=association.klassreflection=association.reflectionscope=klass.unscopedowner=association.ownerchain=get_chain(reflection,association,scope.alias_tracker)scope.extending!reflection.extensionsscope=add_constraints(scope,owner,chain)scope.limit!(1)unlessreflection.collection?scopeenddefself.get_bind_values(owner,chain)binds=[]last_reflection=chain.lastbinds<<last_reflection.join_id_for(owner)iflast_reflection.typebinds<<owner.class.polymorphic_nameendchain.each_cons(2).eachdo|reflection,next_reflection|ifreflection.typebinds<<next_reflection.klass.polymorphic_nameendendbindsendprivateattr_reader:value_transformationdefjoin(table,constraint)table.create_join(table,table.create_on(constraint))enddeflast_chain_scope(scope,reflection,owner)join_keys=reflection.join_keyskey=join_keys.keyforeign_key=join_keys.foreign_keytable=reflection.aliased_tablevalue=transform_value(owner[foreign_key])scope=apply_scope(scope,table,key,value)ifreflection.typepolymorphic_type=transform_value(owner.class.polymorphic_name)scope=apply_scope(scope,table,reflection.type,polymorphic_type)endscopeenddeftransform_value(value)value_transformation.call(value)enddefnext_chain_scope(scope,reflection,next_reflection)join_keys=reflection.join_keyskey=join_keys.keyforeign_key=join_keys.foreign_keytable=reflection.aliased_tableforeign_table=next_reflection.aliased_tableconstraint=table[key].eq(foreign_table[foreign_key])ifreflection.typevalue=transform_value(next_reflection.klass.polymorphic_name)scope=apply_scope(scope,table,reflection.type,value)endscope.joins!(join(foreign_table,constraint))endclassReflectionProxy<SimpleDelegator# :nodoc:attr_reader:aliased_tabledefinitialize(reflection,aliased_table)super(reflection)@aliased_table=aliased_tableenddefall_includes;nil;endenddefget_chain(reflection,association,tracker)name=reflection.namechain=[Reflection::RuntimeReflection.new(reflection,association)]reflection.chain.drop(1).eachdo|refl|aliased_table=tracker.aliased_table_for(refl.table_name,refl.alias_candidate(name),refl.klass.type_caster)chain<<ReflectionProxy.new(refl,aliased_table)endchainenddefadd_constraints(scope,owner,chain)scope=last_chain_scope(scope,chain.last,owner)chain.each_cons(2)do|reflection,next_reflection|scope=next_chain_scope(scope,reflection,next_reflection)endchain_head=chain.firstchain.reverse_eachdo|reflection|# Exclude the scope of the association itself, because that# was already merged in the #scope method.reflection.constraints.eachdo|scope_chain_item|item=eval_scope(reflection,scope_chain_item,owner)ifscope_chain_item==chain_head.scopescope.merge!item.except(:where,:includes,:unscope,:order)endreflection.all_includesdoscope.includes!item.includes_valuesendscope.unscope!(*item.unscope_values)scope.where_clause+=item.where_clausescope.order_values=item.order_values|scope.order_valuesendendscopeenddefapply_scope(scope,table,key,value)ifscope.table==tablescope.where!(key=>value)elsescope.where!(table.name=>{key=>value})endenddefeval_scope(reflection,scope,owner)relation=reflection.build_scope(reflection.aliased_table)relation.instance_exec(owner,&scope)||relationendendendend