ransack 5.0.1 → 6.0.0
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.
- checksums.yaml +4 -4
- data/README.md +13 -27
- data/lib/ransack/active_record/base.rb +154 -0
- data/lib/ransack/active_record/context.rb +504 -0
- data/lib/ransack/active_record/dialect.rb +83 -0
- data/lib/ransack/active_record/join.rb +75 -0
- data/lib/ransack/active_record/join_association.rb +104 -0
- data/lib/ransack/active_record/join_dependency.rb +123 -0
- data/lib/ransack/active_record/reflection.rb +18 -0
- data/lib/ransack/active_record/tree_node.rb +13 -0
- data/lib/ransack/active_record.rb +44 -9
- data/lib/ransack/configuration.rb +49 -1
- data/lib/ransack/constants.rb +61 -0
- data/lib/ransack/context.rb +170 -35
- data/lib/ransack/helpers/form_builder.rb +30 -25
- data/lib/ransack/nodes/bindable.rb +0 -1
- data/lib/ransack/nodes/condition.rb +215 -73
- data/lib/ransack/nodes/grouping.rb +35 -11
- data/lib/ransack/nodes/sort.rb +1 -1
- data/lib/ransack/nodes/value.rb +8 -1
- data/lib/ransack/predicate.rb +8 -1
- data/lib/ransack/search.rb +52 -9
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack.rb +4 -1
- metadata +11 -13
- data/lib/polyamorous/activerecord/join_association.rb +0 -70
- data/lib/polyamorous/activerecord/join_association_7_2.rb +0 -55
- data/lib/polyamorous/activerecord/join_dependency.rb +0 -102
- data/lib/polyamorous/activerecord/reflection.rb +0 -11
- data/lib/polyamorous/join.rb +0 -70
- data/lib/polyamorous/polyamorous.rb +0 -27
- data/lib/polyamorous/swapping_reflection_class.rb +0 -11
- data/lib/polyamorous/tree_node.rb +0 -7
- data/lib/ransack/adapters/active_record/base.rb +0 -152
- data/lib/ransack/adapters/active_record/context.rb +0 -375
data/lib/ransack/search.rb
CHANGED
|
@@ -22,6 +22,11 @@ module Ransack
|
|
|
22
22
|
|
|
23
23
|
def initialize(object, params = {}, options = {})
|
|
24
24
|
strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
|
|
25
|
+
# Strong parameters carry whether the controller permitted them. Read
|
|
26
|
+
# that before the unwrap below discards it: a model with no allowlist
|
|
27
|
+
# of its own lets a permitted controller be the boundary, and a plain
|
|
28
|
+
# Hash never counts (#1403).
|
|
29
|
+
permitted = params.respond_to?(:permitted?) && params.permitted?
|
|
25
30
|
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
26
31
|
if params.is_a? Hash
|
|
27
32
|
# deep_transform_values rebuilds every nested hash and array, which
|
|
@@ -36,7 +41,9 @@ module Ransack
|
|
|
36
41
|
end
|
|
37
42
|
@context = options[:context] || Context.for(object, options)
|
|
38
43
|
@context.auth_object = options[:auth_object]
|
|
44
|
+
@context.permitted = permitted
|
|
39
45
|
@context.ignore_unknown_conditions = options[:ignore_unknown_conditions]
|
|
46
|
+
@context.null_sentinel = options[:null_sentinel]
|
|
40
47
|
@base = Nodes::Grouping.new(
|
|
41
48
|
@context, options[:grouping] || Constants::AND
|
|
42
49
|
)
|
|
@@ -65,7 +72,10 @@ module Ransack
|
|
|
65
72
|
self
|
|
66
73
|
end
|
|
67
74
|
|
|
75
|
+
# Replaces the sorts, so `search.sorts = []` clears them. Before 6.0 each
|
|
76
|
+
# assignment appended (#994); use `build_sort` to add one.
|
|
68
77
|
def sorts=(args)
|
|
78
|
+
@sorts = [] unless args.is_a?(String)
|
|
69
79
|
case args
|
|
70
80
|
when Array
|
|
71
81
|
args.each do |sort|
|
|
@@ -74,12 +84,11 @@ module Ransack
|
|
|
74
84
|
else
|
|
75
85
|
sort = Nodes::Sort.extract(@context, sort)
|
|
76
86
|
end
|
|
77
|
-
|
|
87
|
+
add_sort(sort) if sort
|
|
78
88
|
end
|
|
79
89
|
when Hash
|
|
80
90
|
args.each do |index, attrs|
|
|
81
|
-
|
|
82
|
-
self.sorts << sort
|
|
91
|
+
add_sort(Nodes::Sort.new(@context).build(attrs))
|
|
83
92
|
end
|
|
84
93
|
when String
|
|
85
94
|
self.sorts = [args]
|
|
@@ -105,22 +114,35 @@ module Ransack
|
|
|
105
114
|
Nodes::Sort.new(@context).build(opts)
|
|
106
115
|
end
|
|
107
116
|
|
|
117
|
+
# A scope wins over an attribute of the same name, as it does when the
|
|
118
|
+
# params hash is built (#1472).
|
|
108
119
|
def method_missing(method_id, *args)
|
|
109
120
|
method_name = method_id.to_s
|
|
110
121
|
getter_name = method_name.sub(/=$/, ''.freeze)
|
|
111
|
-
if
|
|
112
|
-
base.send(method_id, *args)
|
|
113
|
-
elsif @context.ransackable_scope?(getter_name, @context.object)
|
|
122
|
+
if @context.ransackable_scope?(getter_name, @context.object)
|
|
114
123
|
if method_name =~ /=$/
|
|
115
|
-
add_scope getter_name, args
|
|
124
|
+
add_scope getter_name, args.size == 1 ? args.first : args
|
|
116
125
|
else
|
|
117
126
|
@scope_args[method_name]
|
|
118
127
|
end
|
|
128
|
+
elsif base.attribute_method?(getter_name)
|
|
129
|
+
base.send(method_id, *args)
|
|
119
130
|
else
|
|
120
131
|
super
|
|
121
132
|
end
|
|
122
133
|
end
|
|
123
134
|
|
|
135
|
+
# Rails' form helpers only read a field's value back when the object
|
|
136
|
+
# says it responds to the reader; `form_with` in particular checks
|
|
137
|
+
# before calling. Mirror method_missing so a search_form_with field is
|
|
138
|
+
# pre-filled the same way a search_form_for one is.
|
|
139
|
+
def respond_to_missing?(method_id, include_private = false)
|
|
140
|
+
getter_name = method_id.to_s.sub(/=$/, ''.freeze)
|
|
141
|
+
base.attribute_method?(getter_name) ||
|
|
142
|
+
@context.ransackable_scope?(getter_name, @context.object) ||
|
|
143
|
+
super
|
|
144
|
+
end
|
|
145
|
+
|
|
124
146
|
def inspect
|
|
125
147
|
details = [
|
|
126
148
|
[:class, klass.name],
|
|
@@ -136,6 +158,22 @@ module Ransack
|
|
|
136
158
|
|
|
137
159
|
private
|
|
138
160
|
|
|
161
|
+
# A sort that names neither a sortable attribute nor a `sort_by_<name>_<dir>`
|
|
162
|
+
# scope produces no ORDER BY. Under a strict search that is an error, the
|
|
163
|
+
# same as an unknown attribute in a condition (#1427); otherwise it is
|
|
164
|
+
# dropped as before.
|
|
165
|
+
def add_sort(sort)
|
|
166
|
+
if @context.strict_conditions? && !sort.valid? && !sort_scope?(sort)
|
|
167
|
+
raise InvalidSearchError, "Invalid sort term #{sort.name}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
self.sorts << sort
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def sort_scope?(sort)
|
|
174
|
+
@context.object.respond_to?(:"sort_by_#{sort.name}_#{sort.dir}")
|
|
175
|
+
end
|
|
176
|
+
|
|
139
177
|
def add_scope(key, args)
|
|
140
178
|
sanitized_args = @context.sanitize_scope_args(key, args)
|
|
141
179
|
|
|
@@ -242,9 +280,14 @@ module Ransack
|
|
|
242
280
|
end
|
|
243
281
|
|
|
244
282
|
# Values in the `c:` API may be given bare or wrapped in a `{ value: ... }`
|
|
245
|
-
# envelope, the same two forms `Condition#values=` accepts.
|
|
283
|
+
# envelope, the same two forms `Condition#values=` accepts. The envelope is
|
|
284
|
+
# opened by key rather than by truthiness: `false` is a value to search
|
|
285
|
+
# for, and `value[:value] || value['value']` read it as nil, which the
|
|
286
|
+
# pruning above then dropped (#1736).
|
|
246
287
|
def unwrap_value(value)
|
|
247
|
-
value.is_a?(Hash)
|
|
288
|
+
return value unless value.is_a?(Hash)
|
|
289
|
+
|
|
290
|
+
value.key?(:value) ? value[:value] : value['value']
|
|
248
291
|
end
|
|
249
292
|
end
|
|
250
293
|
end
|
data/lib/ransack/version.rb
CHANGED
data/lib/ransack.rb
CHANGED
|
@@ -4,11 +4,14 @@ require 'active_support/deprecator'
|
|
|
4
4
|
|
|
5
5
|
require 'active_support/core_ext'
|
|
6
6
|
require 'ransack/configuration'
|
|
7
|
-
require 'polyamorous/polyamorous'
|
|
8
7
|
|
|
9
8
|
module Ransack
|
|
10
9
|
extend Configuration
|
|
11
10
|
class UntraversableAssociationError < StandardError; end
|
|
11
|
+
|
|
12
|
+
def self.deprecator
|
|
13
|
+
@deprecator ||= ActiveSupport::Deprecation.new('7.0', 'Ransack')
|
|
14
|
+
end
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
Ransack.configure do |config|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ransack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ernie Miller
|
|
@@ -62,25 +62,23 @@ email:
|
|
|
62
62
|
- ernie@erniemiller.org
|
|
63
63
|
- radarlistener@gmail.com
|
|
64
64
|
- jonnyatack@gmail.com
|
|
65
|
-
-
|
|
65
|
+
- sean@immersive-app.com
|
|
66
66
|
executables: []
|
|
67
67
|
extensions: []
|
|
68
68
|
extra_rdoc_files: []
|
|
69
69
|
files:
|
|
70
70
|
- LICENSE
|
|
71
71
|
- README.md
|
|
72
|
-
- lib/polyamorous/activerecord/join_association.rb
|
|
73
|
-
- lib/polyamorous/activerecord/join_association_7_2.rb
|
|
74
|
-
- lib/polyamorous/activerecord/join_dependency.rb
|
|
75
|
-
- lib/polyamorous/activerecord/reflection.rb
|
|
76
|
-
- lib/polyamorous/join.rb
|
|
77
|
-
- lib/polyamorous/polyamorous.rb
|
|
78
|
-
- lib/polyamorous/swapping_reflection_class.rb
|
|
79
|
-
- lib/polyamorous/tree_node.rb
|
|
80
72
|
- lib/ransack.rb
|
|
81
73
|
- lib/ransack/active_record.rb
|
|
82
|
-
- lib/ransack/
|
|
83
|
-
- lib/ransack/
|
|
74
|
+
- lib/ransack/active_record/base.rb
|
|
75
|
+
- lib/ransack/active_record/context.rb
|
|
76
|
+
- lib/ransack/active_record/dialect.rb
|
|
77
|
+
- lib/ransack/active_record/join.rb
|
|
78
|
+
- lib/ransack/active_record/join_association.rb
|
|
79
|
+
- lib/ransack/active_record/join_dependency.rb
|
|
80
|
+
- lib/ransack/active_record/reflection.rb
|
|
81
|
+
- lib/ransack/active_record/tree_node.rb
|
|
84
82
|
- lib/ransack/configuration.rb
|
|
85
83
|
- lib/ransack/constants.rb
|
|
86
84
|
- lib/ransack/context.rb
|
|
@@ -142,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
142
140
|
requirements:
|
|
143
141
|
- - ">="
|
|
144
142
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: '3.
|
|
143
|
+
version: '3.2'
|
|
146
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
145
|
requirements:
|
|
148
146
|
- - ">="
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
module Polyamorous
|
|
2
|
-
module JoinAssociationExtensions
|
|
3
|
-
include SwappingReflectionClass
|
|
4
|
-
def self.prepended(base)
|
|
5
|
-
base.class_eval { attr_reader :join_type }
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def initialize(reflection, children, polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin)
|
|
9
|
-
@join_type = join_type
|
|
10
|
-
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
|
|
11
|
-
swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
|
|
12
|
-
super(reflection, children)
|
|
13
|
-
self.reflection.options[:polymorphic] = true
|
|
14
|
-
end
|
|
15
|
-
else
|
|
16
|
-
super(reflection, children)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Same as #join_constraints, but instead of constructing tables from the
|
|
21
|
-
# given block, uses the ones passed
|
|
22
|
-
def join_constraints_with_tables(foreign_table, foreign_klass, join_type, alias_tracker, tables)
|
|
23
|
-
joins = []
|
|
24
|
-
chain = []
|
|
25
|
-
|
|
26
|
-
reflection.chain.each.with_index do |reflection, i|
|
|
27
|
-
table = tables[i]
|
|
28
|
-
|
|
29
|
-
@table ||= table
|
|
30
|
-
chain << [reflection, table]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# The chain starts with the target table, but we want to end with it here (makes
|
|
34
|
-
# more sense in this context), so we reverse
|
|
35
|
-
chain.reverse_each do |reflection, table|
|
|
36
|
-
klass = reflection.klass
|
|
37
|
-
|
|
38
|
-
join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
|
39
|
-
|
|
40
|
-
unless join_scope.references_values.empty?
|
|
41
|
-
join_dependency = join_scope.construct_join_dependency(
|
|
42
|
-
join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
|
|
43
|
-
)
|
|
44
|
-
join_scope.joins!(join_dependency)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
arel = join_scope.arel(alias_tracker.aliases)
|
|
48
|
-
nodes = arel.constraints.first
|
|
49
|
-
|
|
50
|
-
if nodes.is_a?(Arel::Nodes::And)
|
|
51
|
-
others = nodes.children.extract! do |node|
|
|
52
|
-
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
joins << table.create_join(table, table.create_on(nodes), join_type)
|
|
57
|
-
|
|
58
|
-
if others && !others.empty?
|
|
59
|
-
joins.concat arel.join_sources
|
|
60
|
-
append_constraints(joins.last, others)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# The current table in this iteration becomes the foreign table in the next
|
|
64
|
-
foreign_table, foreign_klass = table, klass
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
joins
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
module Polyamorous
|
|
2
|
-
module JoinAssociationExtensions
|
|
3
|
-
# Same as #join_constraints, but instead of constructing tables from the
|
|
4
|
-
# given block, uses the ones passed
|
|
5
|
-
def join_constraints_with_tables(foreign_table, foreign_klass, join_type, alias_tracker, tables)
|
|
6
|
-
joins = []
|
|
7
|
-
chain = []
|
|
8
|
-
|
|
9
|
-
reflection.chain.each.with_index do |reflection, i|
|
|
10
|
-
table = tables[i]
|
|
11
|
-
|
|
12
|
-
@table ||= table
|
|
13
|
-
chain << [reflection, table]
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
base_klass.with_connection do |connection|
|
|
17
|
-
# The chain starts with the target table, but we want to end with it here (makes
|
|
18
|
-
# more sense in this context), so we reverse
|
|
19
|
-
chain.reverse_each do |reflection, table|
|
|
20
|
-
klass = reflection.klass
|
|
21
|
-
|
|
22
|
-
join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
|
23
|
-
|
|
24
|
-
unless join_scope.references_values.empty?
|
|
25
|
-
join_dependency = join_scope.construct_join_dependency(
|
|
26
|
-
join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
|
|
27
|
-
)
|
|
28
|
-
join_scope.joins!(join_dependency)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
arel = join_scope.arel(alias_tracker.aliases)
|
|
32
|
-
nodes = arel.constraints.first
|
|
33
|
-
|
|
34
|
-
if nodes.is_a?(Arel::Nodes::And)
|
|
35
|
-
others = nodes.children.extract! do |node|
|
|
36
|
-
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
joins << table.create_join(table, table.create_on(nodes), join_type)
|
|
41
|
-
|
|
42
|
-
if others && !others.empty?
|
|
43
|
-
joins.concat arel.join_sources
|
|
44
|
-
append_constraints(connection, joins.last, others)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# The current table in this iteration becomes the foreign table in the next
|
|
48
|
-
foreign_table, foreign_klass = table, klass
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
joins
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
module Polyamorous
|
|
2
|
-
module JoinDependencyExtensions
|
|
3
|
-
# Replaces ActiveRecord::Associations::JoinDependency#build
|
|
4
|
-
def build(associations, base_klass)
|
|
5
|
-
associations.map do |name, right|
|
|
6
|
-
if name.is_a? Join
|
|
7
|
-
reflection = find_reflection base_klass, name.name
|
|
8
|
-
reflection.check_validity!
|
|
9
|
-
reflection.check_eager_loadable!
|
|
10
|
-
|
|
11
|
-
klass = if reflection.polymorphic?
|
|
12
|
-
name.klass || base_klass
|
|
13
|
-
else
|
|
14
|
-
reflection.klass
|
|
15
|
-
end
|
|
16
|
-
JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
|
|
17
|
-
else
|
|
18
|
-
reflection = find_reflection base_klass, name
|
|
19
|
-
reflection.check_validity!
|
|
20
|
-
reflection.check_eager_loadable!
|
|
21
|
-
|
|
22
|
-
if reflection.polymorphic?
|
|
23
|
-
raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
|
|
24
|
-
end
|
|
25
|
-
JoinAssociation.new(reflection, build(right, reflection.klass))
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def join_constraints(joins_to_add, alias_tracker, references)
|
|
31
|
-
@alias_tracker = alias_tracker
|
|
32
|
-
@joined_tables = {}
|
|
33
|
-
@references = {}
|
|
34
|
-
|
|
35
|
-
references.each do |table_name|
|
|
36
|
-
@references[table_name.to_sym] = table_name if table_name.is_a?(String)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
joins = make_join_constraints(join_root, join_type)
|
|
40
|
-
|
|
41
|
-
joins.concat joins_to_add.flat_map { |oj|
|
|
42
|
-
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
|
43
|
-
walk join_root, oj.join_root, oj.join_type
|
|
44
|
-
else
|
|
45
|
-
make_join_constraints(oj.join_root, oj.join_type)
|
|
46
|
-
end
|
|
47
|
-
}
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def construct_tables_for_association!(join_root, association)
|
|
51
|
-
tables = table_aliases_for(join_root, association)
|
|
52
|
-
association.table = tables.first
|
|
53
|
-
tables
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
def table_aliases_for(parent, node)
|
|
59
|
-
@joined_tables ||= {}
|
|
60
|
-
node.reflection.chain.map { |reflection|
|
|
61
|
-
table, terminated = @joined_tables[reflection]
|
|
62
|
-
root = reflection == node.reflection
|
|
63
|
-
|
|
64
|
-
if table && (!root || !terminated)
|
|
65
|
-
@joined_tables[reflection] = [table, true] if root
|
|
66
|
-
table
|
|
67
|
-
else
|
|
68
|
-
table = alias_tracker.aliased_table_for(reflection.klass.arel_table) do
|
|
69
|
-
name = reflection.alias_candidate(parent.table_name)
|
|
70
|
-
root ? name : "#{name}_join"
|
|
71
|
-
end
|
|
72
|
-
@joined_tables[reflection] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
|
|
73
|
-
table
|
|
74
|
-
end
|
|
75
|
-
}
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
module ClassMethods
|
|
79
|
-
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
|
80
|
-
#
|
|
81
|
-
def walk_tree(associations, hash)
|
|
82
|
-
case associations
|
|
83
|
-
when TreeNode
|
|
84
|
-
associations.add_to_tree(hash)
|
|
85
|
-
when Hash
|
|
86
|
-
associations.each do |k, v|
|
|
87
|
-
cache =
|
|
88
|
-
if TreeNode === k
|
|
89
|
-
k.add_to_tree(hash)
|
|
90
|
-
else
|
|
91
|
-
hash[k] ||= {}
|
|
92
|
-
end
|
|
93
|
-
walk_tree(v, cache)
|
|
94
|
-
end
|
|
95
|
-
else
|
|
96
|
-
super(associations, hash)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
end
|
|
102
|
-
end
|
data/lib/polyamorous/join.rb
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
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
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
ActiveSupport.on_load(:active_record) do
|
|
2
|
-
module Polyamorous
|
|
3
|
-
InnerJoin = Arel::Nodes::InnerJoin
|
|
4
|
-
OuterJoin = Arel::Nodes::OuterJoin
|
|
5
|
-
|
|
6
|
-
JoinDependency = ::ActiveRecord::Associations::JoinDependency
|
|
7
|
-
JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
require 'polyamorous/tree_node'
|
|
11
|
-
require 'polyamorous/join'
|
|
12
|
-
require 'polyamorous/swapping_reflection_class'
|
|
13
|
-
|
|
14
|
-
require 'polyamorous/activerecord/join_association'
|
|
15
|
-
require 'polyamorous/activerecord/join_dependency'
|
|
16
|
-
require 'polyamorous/activerecord/reflection'
|
|
17
|
-
|
|
18
|
-
if ::ActiveRecord.version >= ::Gem::Version.new("7.2") && ::ActiveRecord.version < ::Gem::Version.new("7.2.2.1")
|
|
19
|
-
require "polyamorous/activerecord/join_association_7_2"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
ActiveRecord::Reflection::AbstractReflection.send(:prepend, Polyamorous::ReflectionExtensions)
|
|
23
|
-
|
|
24
|
-
Polyamorous::JoinDependency.send(:prepend, Polyamorous::JoinDependencyExtensions)
|
|
25
|
-
Polyamorous::JoinDependency.singleton_class.send(:prepend, Polyamorous::JoinDependencyExtensions::ClassMethods)
|
|
26
|
-
Polyamorous::JoinAssociation.send(:prepend, Polyamorous::JoinAssociationExtensions)
|
|
27
|
-
end
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
module Polyamorous
|
|
2
|
-
module SwappingReflectionClass
|
|
3
|
-
def swapping_reflection_klass(reflection, klass)
|
|
4
|
-
new_reflection = reflection.clone
|
|
5
|
-
new_reflection.instance_variable_set(:@options, reflection.options.clone)
|
|
6
|
-
new_reflection.options.delete(:polymorphic)
|
|
7
|
-
new_reflection.instance_variable_set(:@klass, klass)
|
|
8
|
-
yield new_reflection
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|