forked from activerecord-hackery/ransack
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request activerecord-hackery#927 from gregmolnar/polyamorous
absorb polyamorous
- Loading branch information
Showing
29 changed files
with
1,056 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
if defined?(::ActiveRecord) | ||
module Polyamorous | ||
if defined?(Arel::InnerJoin) | ||
InnerJoin = Arel::InnerJoin | ||
OuterJoin = Arel::OuterJoin | ||
else | ||
InnerJoin = Arel::Nodes::InnerJoin | ||
OuterJoin = Arel::Nodes::OuterJoin | ||
end | ||
|
||
if defined?(::ActiveRecord::Associations::JoinDependency) | ||
JoinDependency = ::ActiveRecord::Associations::JoinDependency | ||
JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation | ||
JoinBase = ::ActiveRecord::Associations::JoinDependency::JoinBase | ||
else | ||
JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency | ||
JoinAssociation = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation | ||
JoinBase = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase | ||
end | ||
end | ||
|
||
require 'polyamorous/tree_node' | ||
require 'polyamorous/join' | ||
require 'polyamorous/swapping_reflection_class' | ||
|
||
ar_version = ::ActiveRecord::VERSION::STRING[0,3] | ||
ar_version = '3_and_4.0' if ar_version < '4.1' | ||
ar_version = ::ActiveRecord::VERSION::STRING[0,5] if ar_version == '5.2' | ||
|
||
method, ruby_version = | ||
if RUBY_VERSION >= '2.0' && ar_version >= '4.1' | ||
# Ruby 2; we can use `prepend` to patch Active Record cleanly. | ||
[:prepend, '2'] | ||
else | ||
# Ruby 1.9; we must use `alias_method` to patch Active Record. | ||
[:include, '1.9'] | ||
end | ||
|
||
%w(join_association join_dependency).each do |file| | ||
require "polyamorous/activerecord_#{ar_version}_ruby_#{ruby_version}/#{file}" | ||
end | ||
|
||
Polyamorous::JoinDependency.send(method, Polyamorous::JoinDependencyExtensions) | ||
if method == :prepend | ||
Polyamorous::JoinDependency.singleton_class | ||
.send(:prepend, Polyamorous::JoinDependencyExtensions::ClassMethods) | ||
end | ||
Polyamorous::JoinAssociation.send(method, Polyamorous::JoinAssociationExtensions) | ||
|
||
Polyamorous::JoinBase.class_eval do | ||
if method_defined?(:active_record) | ||
alias_method :base_klass, :active_record | ||
end | ||
end | ||
end |
76 changes: 76 additions & 0 deletions
76
lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_association.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# active_record_3_and_4.0_ruby_1.9/join_association.rb | ||
module Polyamorous | ||
module JoinAssociationExtensions | ||
include SwappingReflectionClass | ||
def self.included(base) | ||
base.class_eval do | ||
alias_method_chain :initialize, :polymorphism | ||
alias_method :equality_without_polymorphism, :== | ||
alias_method :==, :equality_with_polymorphism | ||
if base.method_defined?(:active_record) | ||
alias_method :base_klass, :active_record | ||
end | ||
|
||
if ActiveRecord::VERSION::STRING =~ /^3\.0\./ | ||
alias_method_chain :association_join, :polymorphism | ||
else | ||
alias_method_chain :build_constraint, :polymorphism | ||
end | ||
end | ||
end | ||
|
||
def initialize_with_polymorphism( | ||
reflection, join_dependency, parent = nil, polymorphic_class = nil | ||
) | ||
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class | ||
swapping_reflection_klass(reflection, polymorphic_class) do |reflection| | ||
initialize_without_polymorphism(reflection, join_dependency, parent) | ||
self.reflection.options[:polymorphic] = true | ||
end | ||
else | ||
initialize_without_polymorphism(reflection, join_dependency, parent) | ||
end | ||
end | ||
|
||
def equality_with_polymorphism(other) | ||
equality_without_polymorphism(other) && base_klass == other.base_klass | ||
end | ||
|
||
def build_constraint_with_polymorphism( | ||
reflection, table, key, foreign_table, foreign_key | ||
) | ||
if reflection.options[:polymorphic] | ||
build_constraint_without_polymorphism( | ||
reflection, table, key, foreign_table, foreign_key | ||
) | ||
.and(foreign_table[reflection.foreign_type].eq(reflection.klass.name)) | ||
else | ||
build_constraint_without_polymorphism( | ||
reflection, table, key, foreign_table, foreign_key | ||
) | ||
end | ||
end | ||
|
||
def association_join_with_polymorphism | ||
return @join if @Join | ||
@join = association_join_without_polymorphism | ||
if reflection.macro == :belongs_to && reflection.options[:polymorphic] | ||
aliased_table = Arel::Table.new( | ||
table_name, | ||
as: @aliased_table_name, | ||
engine: arel_engine, | ||
columns: klass.columns | ||
) | ||
parent_table = Arel::Table.new( | ||
parent.table_name, | ||
as: parent.aliased_table_name, | ||
engine: arel_engine, | ||
columns: parent.base_klass.columns | ||
) | ||
@join << parent_table[reflection.options[:foreign_type]] | ||
.eq(reflection.klass.name) | ||
end | ||
@join | ||
end | ||
end | ||
end |
96 changes: 96 additions & 0 deletions
96
lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_dependency.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# active_record_3_and_4.0_ruby_1.9/join_dependency.rb | ||
module Polyamorous | ||
module JoinDependencyExtensions | ||
def self.included(base) | ||
base.class_eval do | ||
alias_method_chain :build, :polymorphism | ||
alias_method_chain :graft, :polymorphism | ||
if base.method_defined?(:active_record) | ||
alias_method :base_klass, :active_record | ||
end | ||
end | ||
end | ||
|
||
def graft_with_polymorphism(*associations) | ||
associations.each do |association| | ||
unless join_associations.detect { |a| association == a } | ||
if association.reflection.options[:polymorphic] | ||
build( | ||
Join.new( | ||
association.reflection.name, | ||
association.join_type, | ||
association.reflection.klass | ||
), | ||
association.find_parent_in(self) || join_base, | ||
association.join_type | ||
) | ||
else | ||
build( | ||
association.reflection.name, | ||
association.find_parent_in(self) || join_base, | ||
association.join_type | ||
) | ||
end | ||
end | ||
end | ||
self | ||
end | ||
|
||
if ActiveRecord::VERSION::STRING =~ /^3\.0\./ | ||
def _join_parts | ||
@joins | ||
end | ||
else | ||
def _join_parts | ||
@join_parts | ||
end | ||
end | ||
|
||
def build_with_polymorphism( | ||
associations, parent = nil, join_type = InnerJoin | ||
) | ||
case associations | ||
when Join | ||
parent ||= _join_parts.last | ||
reflection = parent.reflections[associations.name] or | ||
raise ::ActiveRecord::ConfigurationError, | ||
"Association named '#{associations.name | ||
}' was not found; perhaps you misspelled it?" | ||
|
||
unless join_association = find_join_association_respecting_polymorphism( | ||
reflection, parent, associations.klass | ||
) | ||
@reflections << reflection | ||
join_association = build_join_association_respecting_polymorphism( | ||
reflection, parent, associations.klass | ||
) | ||
join_association.join_type = associations.type | ||
_join_parts << join_association | ||
cache_joined_association(join_association) | ||
end | ||
|
||
join_association | ||
else | ||
build_without_polymorphism(associations, parent, join_type) | ||
end | ||
end | ||
|
||
def find_join_association_respecting_polymorphism(reflection, parent, klass) | ||
if association = find_join_association(reflection, parent) | ||
unless reflection.options[:polymorphic] | ||
association | ||
else | ||
association if association.base_klass == klass | ||
end | ||
end | ||
end | ||
|
||
def build_join_association_respecting_polymorphism(reflection, parent, klass) | ||
if reflection.options[:polymorphic] && klass | ||
JoinAssociation.new(reflection, self, parent, klass) | ||
else | ||
JoinAssociation.new(reflection, self, parent) | ||
end | ||
end | ||
end | ||
end |
2 changes: 2 additions & 0 deletions
2
lib/polyamorous/activerecord_4.1_ruby_1.9/join_association.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# active_record_4.1_ruby_1.9/join_association.rb | ||
require 'polyamorous/activerecord_4.2_ruby_1.9/join_association' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# active_record_4.1_ruby_1.9/join_dependency.rb | ||
require 'polyamorous/activerecord_4.2_ruby_2/join_dependency' | ||
require 'polyamorous/activerecord_4.2_ruby_1.9/join_dependency' | ||
require 'polyamorous/activerecord_4.1_ruby_2/make_polyamorous_inner_joins' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# active_record_4.1_ruby_2/join_association.rb | ||
require 'polyamorous/activerecord_5.0_ruby_2/join_association' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# active_record_4.1_ruby_2/join_dependency.rb | ||
require 'polyamorous/activerecord_4.2_ruby_2/join_dependency' | ||
require 'polyamorous/activerecord_4.1_ruby_2/make_polyamorous_inner_joins' |
14 changes: 14 additions & 0 deletions
14
lib/polyamorous/activerecord_4.1_ruby_2/make_polyamorous_inner_joins.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module Polyamorous | ||
module JoinDependencyExtensions | ||
# Replaces ActiveRecord::Associations::JoinDependency#make_inner_joins | ||
# | ||
def make_polyamorous_inner_joins(parent, child) | ||
make_constraints( | ||
parent, child, child.tables, child.join_type || Arel::Nodes::InnerJoin | ||
) | ||
.concat child.children.flat_map { |c| | ||
make_polyamorous_inner_joins(child, c) | ||
} | ||
end | ||
end | ||
end |
46 changes: 46 additions & 0 deletions
46
lib/polyamorous/activerecord_4.2_ruby_1.9/join_association.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# active_record_4.2_ruby_1.9/join_association.rb | ||
module Polyamorous | ||
module JoinAssociationExtensions | ||
include SwappingReflectionClass | ||
def self.included(base) | ||
base.class_eval do | ||
attr_reader :join_type | ||
alias_method_chain :initialize, :polymorphism | ||
alias_method_chain :build_constraint, :polymorphism | ||
end | ||
end | ||
|
||
def initialize_with_polymorphism(reflection, children, | ||
polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin) | ||
@join_type = join_type | ||
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class | ||
swapping_reflection_klass(reflection, polymorphic_class) do |reflection| | ||
initialize_without_polymorphism(reflection, children) | ||
self.reflection.options[:polymorphic] = true | ||
end | ||
else | ||
initialize_without_polymorphism(reflection, children) | ||
end | ||
end | ||
|
||
# Reference https://github.com/rails/rails/commit/9b15db51b78028bfecdb85595624de4b838adbd1 | ||
def ==(other) | ||
base_klass == other.base_klass | ||
end | ||
|
||
def build_constraint_with_polymorphism( | ||
klass, table, key, foreign_table, foreign_key | ||
) | ||
if reflection.polymorphic? | ||
build_constraint_without_polymorphism( | ||
klass, table, key, foreign_table, foreign_key | ||
) | ||
.and(foreign_table[reflection.foreign_type].eq(reflection.klass.name)) | ||
else | ||
build_constraint_without_polymorphism( | ||
klass, table, key, foreign_table, foreign_key | ||
) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.