ransack 1.8.8 → 1.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -1
  3. data/CHANGELOG.md +4 -0
  4. data/Gemfile +3 -6
  5. data/README.md +37 -0
  6. data/lib/polyamorous.rb +55 -0
  7. data/lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_association.rb +76 -0
  8. data/lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_dependency.rb +96 -0
  9. data/lib/polyamorous/activerecord_4.1_ruby_1.9/join_association.rb +2 -0
  10. data/lib/polyamorous/activerecord_4.1_ruby_1.9/join_dependency.rb +4 -0
  11. data/lib/polyamorous/activerecord_4.1_ruby_2/join_association.rb +2 -0
  12. data/lib/polyamorous/activerecord_4.1_ruby_2/join_dependency.rb +3 -0
  13. data/lib/polyamorous/activerecord_4.1_ruby_2/make_polyamorous_inner_joins.rb +14 -0
  14. data/lib/polyamorous/activerecord_4.2_ruby_1.9/join_association.rb +46 -0
  15. data/lib/polyamorous/activerecord_4.2_ruby_1.9/join_dependency.rb +87 -0
  16. data/lib/polyamorous/activerecord_4.2_ruby_2/join_association.rb +2 -0
  17. data/lib/polyamorous/activerecord_4.2_ruby_2/join_dependency.rb +24 -0
  18. data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +2 -0
  19. data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +2 -0
  20. data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +39 -0
  21. data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +130 -0
  22. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +39 -0
  23. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +131 -0
  24. data/lib/polyamorous/join.rb +70 -0
  25. data/lib/polyamorous/swapping_reflection_class.rb +11 -0
  26. data/lib/polyamorous/tree_node.rb +7 -0
  27. data/lib/ransack/adapters/active_record/3.0/compat.rb +1 -7
  28. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +3 -8
  29. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +1 -7
  30. data/lib/ransack/helpers/form_builder.rb +14 -8
  31. data/lib/ransack/locale/az.yml +70 -0
  32. data/lib/ransack/nodes/grouping.rb +1 -5
  33. data/lib/ransack/version.rb +1 -1
  34. data/lib/ransack/visitor.rb +1 -7
  35. data/ransack.gemspec +3 -5
  36. data/spec/helpers/polyamorous_helper.rb +26 -0
  37. data/spec/ransack/join_association_spec.rb +54 -0
  38. data/spec/ransack/join_dependency_spec.rb +102 -0
  39. data/spec/ransack/join_spec.rb +19 -0
  40. data/spec/spec_helper.rb +1 -0
  41. metadata +51 -17
@@ -0,0 +1,2 @@
1
+ # active_record_4.2_ruby_2/join_association.rb
2
+ require 'polyamorous/activerecord_5.0_ruby_2/join_association'
@@ -0,0 +1,24 @@
1
+ # active_record_4.2_ruby_2/join_dependency.rb
2
+ require 'polyamorous/activerecord_5.0_ruby_2/join_dependency'
3
+
4
+ module Polyamorous
5
+ module JoinDependencyExtensions
6
+ # Replaces ActiveRecord::Associations::JoinDependency#join_constraints
7
+ # to call #make_polyamorous_inner_joins instead of #make_inner_joins.
8
+ #
9
+ def join_constraints(outer_joins)
10
+ joins = join_root.children.flat_map { |child|
11
+ make_polyamorous_inner_joins join_root, child
12
+ }
13
+ joins.concat outer_joins.flat_map { |oj|
14
+ if join_root.match? oj.join_root
15
+ walk(join_root, oj.join_root)
16
+ else
17
+ oj.join_root.children.flat_map { |child|
18
+ make_outer_joins(oj.join_root, child)
19
+ }
20
+ end
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ # active_record_5.0_ruby_2/join_association.rb
2
+ require 'polyamorous/activerecord_5.1_ruby_2/join_association'
@@ -0,0 +1,2 @@
1
+ # active_record_5.0_ruby_2/join_dependency.rb
2
+ require 'polyamorous/activerecord_5.1_ruby_2/join_dependency'
@@ -0,0 +1,39 @@
1
+ # active_record_5.1_ruby_2/join_association.rb
2
+
3
+ module Polyamorous
4
+ module JoinAssociationExtensions
5
+ include SwappingReflectionClass
6
+ def self.prepended(base)
7
+ base.class_eval { attr_reader :join_type }
8
+ end
9
+
10
+ def initialize(reflection, children, polymorphic_class = nil,
11
+ join_type = Arel::Nodes::InnerJoin)
12
+ @join_type = join_type
13
+ if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
14
+ swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
15
+ super(reflection, children)
16
+ self.reflection.options[:polymorphic] = true
17
+ end
18
+ else
19
+ super(reflection, children)
20
+ end
21
+ end
22
+
23
+ # Reference: https://github.com/rails/rails/commit/9b15db5
24
+ # NOTE: Not sure we still need it?
25
+ #
26
+ def ==(other)
27
+ base_klass == other.base_klass
28
+ end
29
+
30
+ def build_constraint(klass, table, key, foreign_table, foreign_key)
31
+ if reflection.polymorphic?
32
+ super(klass, table, key, foreign_table, foreign_key)
33
+ .and(foreign_table[reflection.foreign_type].eq(reflection.klass.name))
34
+ else
35
+ super(klass, table, key, foreign_table, foreign_key)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,130 @@
1
+ # active_record_5.1_ruby_2/join_dependency.rb
2
+
3
+ module Polyamorous
4
+ module JoinDependencyExtensions
5
+ # Replaces ActiveRecord::Associations::JoinDependency#build
6
+ #
7
+ def build(associations, base_klass)
8
+ associations.map do |name, right|
9
+ if name.is_a? Join
10
+ reflection = find_reflection base_klass, name.name
11
+ reflection.check_validity!
12
+ reflection.check_eager_loadable! if ActiveRecord::VERSION::MAJOR >= 5
13
+
14
+ klass = if reflection.polymorphic?
15
+ name.klass || base_klass
16
+ else
17
+ reflection.klass
18
+ end
19
+ JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
20
+ else
21
+ reflection = find_reflection base_klass, name
22
+ reflection.check_validity!
23
+ reflection.check_eager_loadable! if ActiveRecord::VERSION::MAJOR >= 5
24
+
25
+ if reflection.polymorphic?
26
+ raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
27
+ end
28
+ JoinAssociation.new reflection, build(right, reflection.klass)
29
+ end
30
+ end
31
+ end
32
+
33
+ def find_join_association_respecting_polymorphism(reflection, parent, klass)
34
+ if association = parent.children.find { |j| j.reflection == reflection }
35
+ unless reflection.polymorphic?
36
+ association
37
+ else
38
+ association if association.base_klass == klass
39
+ end
40
+ end
41
+ end
42
+
43
+ def build_join_association_respecting_polymorphism(reflection, parent, klass)
44
+ if reflection.polymorphic? && klass
45
+ JoinAssociation.new(reflection, self, klass)
46
+ else
47
+ JoinAssociation.new(reflection, self)
48
+ end
49
+ end
50
+
51
+ # Replaces ActiveRecord::Associations::JoinDependency#join_constraints
52
+ #
53
+ # This internal method was changed in Rails 5.0 by commit
54
+ # https://github.com/rails/rails/commit/e038975 which added
55
+ # left_outer_joins (see #make_polyamorous_left_outer_joins below) and added
56
+ # passing an additional argument, `join_type`, to #join_constraints.
57
+ #
58
+ def join_constraints(outer_joins, join_type)
59
+ joins = join_root.children.flat_map { |child|
60
+ if join_type == Arel::Nodes::OuterJoin
61
+ make_polyamorous_left_outer_joins join_root, child
62
+ else
63
+ make_polyamorous_inner_joins join_root, child
64
+ end
65
+ }
66
+
67
+ joins.concat outer_joins.flat_map { |oj|
68
+ if join_root.match? oj.join_root
69
+ walk(join_root, oj.join_root)
70
+ else
71
+ oj.join_root.children.flat_map { |child|
72
+ make_outer_joins(oj.join_root, child)
73
+ }
74
+ end
75
+ }
76
+ end
77
+
78
+ # Replaces ActiveRecord::Associations::JoinDependency#make_left_outer_joins,
79
+ # a new method that was added in Rails 5.0 with the following commit:
80
+ # https://github.com/rails/rails/commit/e038975
81
+ #
82
+ def make_polyamorous_left_outer_joins(parent, child)
83
+ tables = child.tables
84
+ join_type = Arel::Nodes::OuterJoin
85
+ info = make_constraints parent, child, tables, join_type
86
+
87
+ [info] + child.children.flat_map { |c|
88
+ make_polyamorous_left_outer_joins(child, c)
89
+ }
90
+ end
91
+
92
+ # Replaces ActiveRecord::Associations::JoinDependency#make_inner_joins
93
+ #
94
+ def make_polyamorous_inner_joins(parent, child)
95
+ tables = child.tables
96
+ join_type = child.join_type || Arel::Nodes::InnerJoin
97
+ info = make_constraints parent, child, tables, join_type
98
+
99
+ [info] + child.children.flat_map { |c|
100
+ make_polyamorous_inner_joins(child, c)
101
+ }
102
+ end
103
+
104
+ private :make_polyamorous_inner_joins, :make_polyamorous_left_outer_joins
105
+
106
+ module ClassMethods
107
+ # Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
108
+ #
109
+ def walk_tree(associations, hash)
110
+ case associations
111
+ when TreeNode
112
+ associations.add_to_tree(hash)
113
+ when Hash
114
+ associations.each do |k, v|
115
+ cache =
116
+ if TreeNode === k
117
+ k.add_to_tree(hash)
118
+ else
119
+ hash[k] ||= {}
120
+ end
121
+ walk_tree(v, cache)
122
+ end
123
+ else
124
+ super(associations, hash)
125
+ end
126
+ end
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,39 @@
1
+ # active_record_5.2_ruby_2/join_association.rb
2
+
3
+ module Polyamorous
4
+ module JoinAssociationExtensions
5
+ include SwappingReflectionClass
6
+ def self.prepended(base)
7
+ base.class_eval { attr_reader :join_type }
8
+ end
9
+
10
+ def initialize(reflection, children, alias_tracker, polymorphic_class = nil,
11
+ join_type = Arel::Nodes::InnerJoin)
12
+ @join_type = join_type
13
+ if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
14
+ swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
15
+ super(reflection, children, alias_tracker)
16
+ self.reflection.options[:polymorphic] = true
17
+ end
18
+ else
19
+ super(reflection, children, alias_tracker)
20
+ end
21
+ end
22
+
23
+ # Reference: https://github.com/rails/rails/commit/9b15db5
24
+ # NOTE: Not sure we still need it?
25
+ #
26
+ def ==(other)
27
+ base_klass == other.base_klass
28
+ end
29
+
30
+ def build_constraint(klass, table, key, foreign_table, foreign_key)
31
+ if reflection.polymorphic?
32
+ super(klass, table, key, foreign_table, foreign_key)
33
+ .and(foreign_table[reflection.foreign_type].eq(reflection.klass.name))
34
+ else
35
+ super(klass, table, key, foreign_table, foreign_key)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,131 @@
1
+ # active_record_5.2_ruby_2/join_dependency.rb
2
+
3
+ module Polyamorous
4
+ module JoinDependencyExtensions
5
+ # Replaces ActiveRecord::Associations::JoinDependency#build
6
+ #
7
+ def build(associations, base_klass)
8
+ associations.map do |name, right|
9
+ if name.is_a? Join
10
+ reflection = find_reflection base_klass, name.name
11
+ reflection.check_validity!
12
+ reflection.check_eager_loadable! if ActiveRecord::VERSION::MAJOR >= 5
13
+
14
+ klass = if reflection.polymorphic?
15
+ name.klass || base_klass
16
+ else
17
+ reflection.klass
18
+ end
19
+ JoinAssociation.new(reflection, build(right, klass), alias_tracker, name.klass, name.type)
20
+ else
21
+ reflection = find_reflection base_klass, name
22
+ reflection.check_validity!
23
+ reflection.check_eager_loadable! if ActiveRecord::VERSION::MAJOR >= 5
24
+
25
+ if reflection.polymorphic?
26
+ raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
27
+ end
28
+ JoinAssociation.new(reflection, build(right, reflection.klass), alias_tracker)
29
+ end
30
+ end
31
+ end
32
+
33
+ def find_join_association_respecting_polymorphism(reflection, parent, klass)
34
+ if association = parent.children.find { |j| j.reflection == reflection }
35
+ unless reflection.polymorphic?
36
+ association
37
+ else
38
+ association if association.base_klass == klass
39
+ end
40
+ end
41
+ end
42
+
43
+ def build_join_association_respecting_polymorphism(reflection, parent, klass)
44
+ if reflection.polymorphic? && klass
45
+ JoinAssociation.new(reflection, self, alias_tracker, klass)
46
+ else
47
+ JoinAssociation.new(reflection, self, alias_tracker)
48
+ end
49
+ end
50
+
51
+ # Replaces ActiveRecord::Associations::JoinDependency#join_constraints
52
+ #
53
+ # This internal method was changed in Rails 5.0 by commit
54
+ # https://github.com/rails/rails/commit/e038975 which added
55
+ # left_outer_joins (see #make_polyamorous_left_outer_joins below) and added
56
+ # passing an additional argument, `join_type`, to #join_constraints.
57
+ #
58
+ def join_constraints(outer_joins, join_type)
59
+ @alias_tracker = alias_tracker
60
+ joins = join_root.children.flat_map { |child|
61
+ if join_type == Arel::Nodes::OuterJoin
62
+ make_polyamorous_left_outer_joins join_root, child
63
+ else
64
+ make_polyamorous_inner_joins join_root, child
65
+ end
66
+ }
67
+
68
+ joins.concat outer_joins.flat_map { |oj|
69
+ if join_root.match? oj.join_root
70
+ walk(join_root, oj.join_root)
71
+ else
72
+ oj.join_root.children.flat_map { |child|
73
+ make_outer_joins(oj.join_root, child)
74
+ }
75
+ end
76
+ }
77
+ end
78
+
79
+ # Replaces ActiveRecord::Associations::JoinDependency#make_left_outer_joins,
80
+ # a new method that was added in Rails 5.0 with the following commit:
81
+ # https://github.com/rails/rails/commit/e038975
82
+ #
83
+ def make_polyamorous_left_outer_joins(parent, child)
84
+ tables = child.tables
85
+ join_type = Arel::Nodes::OuterJoin
86
+ info = make_constraints parent, child, tables, join_type
87
+
88
+ info + child.children.flat_map { |c|
89
+ make_polyamorous_left_outer_joins(child, c)
90
+ }
91
+ end
92
+
93
+ # Replaces ActiveRecord::Associations::JoinDependency#make_inner_joins
94
+ #
95
+ def make_polyamorous_inner_joins(parent, child)
96
+ tables = child.tables
97
+ join_type = child.join_type || Arel::Nodes::InnerJoin
98
+ info = make_constraints parent, child, tables, join_type
99
+
100
+ info + child.children.flat_map { |c|
101
+ make_polyamorous_inner_joins(child, c)
102
+ }
103
+ end
104
+
105
+ private :make_polyamorous_inner_joins, :make_polyamorous_left_outer_joins
106
+
107
+ module ClassMethods
108
+ # Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
109
+ #
110
+ def walk_tree(associations, hash)
111
+ case associations
112
+ when TreeNode
113
+ associations.add_to_tree(hash)
114
+ when Hash
115
+ associations.each do |k, v|
116
+ cache =
117
+ if TreeNode === k
118
+ k.add_to_tree(hash)
119
+ else
120
+ hash[k] ||= {}
121
+ end
122
+ walk_tree(v, cache)
123
+ end
124
+ else
125
+ super(associations, hash)
126
+ end
127
+ end
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,70 @@
1
+ module Polyamorous
2
+ class Join
3
+ include TreeNode
4
+
5
+ attr_accessor :name
6
+ attr_reader :type, :klass
7
+
8
+ def initialize(name, type = InnerJoin, klass = nil)
9
+ @name = name
10
+ @type = convert_to_arel_join_type(type)
11
+ @klass = convert_to_class(klass) if klass
12
+ end
13
+
14
+ def klass=(klass)
15
+ @klass = convert_to_class(klass) if klass
16
+ end
17
+
18
+ def type=(type)
19
+ @type = convert_to_arel_join_type(type) if type
20
+ end
21
+
22
+ def hash
23
+ [@name, @type, @klass].hash
24
+ end
25
+
26
+ def eql?(other)
27
+ self.class == other.class &&
28
+ self.name == other.name &&
29
+ self.type == other.type &&
30
+ self.klass == other.klass
31
+ end
32
+
33
+ alias :== :eql?
34
+
35
+ def add_to_tree(hash)
36
+ hash[self] ||= {}
37
+ end
38
+
39
+ private
40
+
41
+ def convert_to_arel_join_type(type)
42
+ case type
43
+ when 'inner', :inner
44
+ InnerJoin
45
+ when 'outer', :outer
46
+ OuterJoin
47
+ when Class
48
+ if [InnerJoin, OuterJoin].include? type
49
+ type
50
+ else
51
+ raise ArgumentError, "#{type} cannot be converted to an ARel join type"
52
+ end
53
+ else
54
+ raise ArgumentError, "#{type} cannot be converted to an ARel join type"
55
+ end
56
+ end
57
+
58
+ def convert_to_class(value)
59
+ case value
60
+ when String, Symbol
61
+ Kernel.const_get(value)
62
+ when Class
63
+ value
64
+ else
65
+ raise ArgumentError, "#{value} cannot be converted to a Class"
66
+ end
67
+ end
68
+
69
+ end
70
+ end