ransack 1.8.8 → 1.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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