ransack 4.4.0 → 5.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 +3 -2
- data/lib/ransack/adapters/active_record/context.rb +12 -10
- data/lib/ransack/configuration.rb +38 -5
- data/lib/ransack/constants.rb +36 -11
- data/lib/ransack/context.rb +36 -4
- data/lib/ransack/helpers/form_builder.rb +1 -17
- data/lib/ransack/helpers/form_helper.rb +7 -7
- data/lib/ransack/nodes/attribute.rb +11 -2
- data/lib/ransack/nodes/condition.rb +107 -31
- data/lib/ransack/nodes/grouping.rb +23 -5
- data/lib/ransack/nodes/node.rb +13 -0
- data/lib/ransack/nodes/sort.rb +1 -2
- data/lib/ransack/nodes/value.rb +3 -9
- data/lib/ransack/predicate.rb +24 -3
- data/lib/ransack/search.rb +65 -22
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack.rb +1 -5
- metadata +9 -61
- data/spec/blueprints/articles.rb +0 -5
- data/spec/blueprints/comments.rb +0 -5
- data/spec/blueprints/notes.rb +0 -5
- data/spec/blueprints/people.rb +0 -8
- data/spec/blueprints/tags.rb +0 -3
- data/spec/console.rb +0 -25
- data/spec/helpers/polyamorous_helper.rb +0 -13
- data/spec/helpers/ransack_helper.rb +0 -9
- data/spec/polyamorous/activerecord_compatibility_spec.rb +0 -15
- data/spec/polyamorous/join_association_spec.rb +0 -29
- data/spec/polyamorous/join_dependency_spec.rb +0 -80
- data/spec/polyamorous/join_spec.rb +0 -19
- data/spec/ransack/adapters/active_record/base_spec.rb +0 -905
- data/spec/ransack/adapters/active_record/context_spec.rb +0 -219
- data/spec/ransack/configuration_spec.rb +0 -201
- data/spec/ransack/helpers/form_builder_spec.rb +0 -169
- data/spec/ransack/helpers/form_helper_spec.rb +0 -1075
- data/spec/ransack/nodes/condition_spec.rb +0 -333
- data/spec/ransack/nodes/grouping_spec.rb +0 -111
- data/spec/ransack/nodes/value_spec.rb +0 -126
- data/spec/ransack/predicate_spec.rb +0 -504
- data/spec/ransack/search_spec.rb +0 -814
- data/spec/ransack/translate_spec.rb +0 -16
- data/spec/spec_helper.rb +0 -65
- data/spec/support/en.yml +0 -18
- data/spec/support/schema.rb +0 -422
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
module Ransack
|
|
2
2
|
module Nodes
|
|
3
3
|
class Grouping < Node
|
|
4
|
-
attr_reader :
|
|
5
|
-
|
|
4
|
+
attr_reader :combinator
|
|
5
|
+
|
|
6
|
+
# The writer is inherited from Node, which normalises the value. Defining
|
|
7
|
+
# it here as well — or aliasing before the definition is in place — would
|
|
8
|
+
# bind `m=` to the plain attribute writer and skip that normalisation,
|
|
9
|
+
# which is how `g: [{ m: 'OR' }]` silently fell back to AND.
|
|
6
10
|
alias :m :combinator
|
|
7
11
|
alias :m= :combinator=
|
|
8
12
|
|
|
@@ -13,7 +17,7 @@ module Ransack
|
|
|
13
17
|
|
|
14
18
|
def initialize(context, combinator = nil)
|
|
15
19
|
super(context)
|
|
16
|
-
self.combinator = combinator
|
|
20
|
+
self.combinator = combinator if combinator
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def persisted?
|
|
@@ -149,10 +153,14 @@ module Ransack
|
|
|
149
153
|
def build(params)
|
|
150
154
|
params.with_indifferent_access.each do |key, value|
|
|
151
155
|
case key
|
|
152
|
-
when /^(g|c|m)$/
|
|
156
|
+
when /^(g|c|m|groupings|conditions|combinator)$/
|
|
153
157
|
self.send("#{key}=", value)
|
|
154
158
|
else
|
|
155
|
-
|
|
159
|
+
if @context.ransackable_scope?(key, @context.object)
|
|
160
|
+
@context.chain_scope(key, @context.sanitize_scope_args(key, value))
|
|
161
|
+
else
|
|
162
|
+
write_attribute(key.to_s, value)
|
|
163
|
+
end
|
|
156
164
|
end
|
|
157
165
|
end
|
|
158
166
|
self
|
|
@@ -178,6 +186,16 @@ module Ransack
|
|
|
178
186
|
end
|
|
179
187
|
|
|
180
188
|
def read_attribute(name)
|
|
189
|
+
# A field built from an aliased attribute writes its value under the real
|
|
190
|
+
# name but reads it back under the alias. Resolve the alias so the
|
|
191
|
+
# value survives a form round-trip (#689).
|
|
192
|
+
if self[name].nil?
|
|
193
|
+
stripped_name = name.dup
|
|
194
|
+
predicate = Predicate.detect_and_strip_from_string!(stripped_name)
|
|
195
|
+
aliased_attribute = context.ransackable_alias(stripped_name)
|
|
196
|
+
name = "#{aliased_attribute}_#{predicate}" unless aliased_attribute == stripped_name
|
|
197
|
+
end
|
|
198
|
+
|
|
181
199
|
if self[name].respond_to?(:value)
|
|
182
200
|
self[name].value
|
|
183
201
|
else
|
data/lib/ransack/nodes/node.rb
CHANGED
|
@@ -29,6 +29,19 @@ module Ransack
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Every way of supplying a combinator — a top-level `combinator`/`m`,
|
|
33
|
+
# or an `m` inside any nested grouping or condition — ends up here, so
|
|
34
|
+
# this is the one place that normalises the spelling and, when the search
|
|
35
|
+
# is strict, rejects a value it does not recognise.
|
|
36
|
+
def combinator=(val)
|
|
37
|
+
normalised = val.to_s.downcase
|
|
38
|
+
@combinator = Constants::AND_OR.detect { |v| v == normalised }
|
|
39
|
+
|
|
40
|
+
if @combinator.nil? && !normalised.empty? && context&.strict_conditions?
|
|
41
|
+
raise InvalidSearchError, "Invalid combinator #{val}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
32
45
|
end
|
|
33
46
|
end
|
|
34
47
|
end
|
data/lib/ransack/nodes/sort.rb
CHANGED
|
@@ -26,8 +26,7 @@ module Ransack
|
|
|
26
26
|
|
|
27
27
|
def valid?
|
|
28
28
|
bound? && attr &&
|
|
29
|
-
|
|
30
|
-
.include?(attr_name)
|
|
29
|
+
context.ransortable_attribute?(attr_name.split('.').last, context.klassify(parent))
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
def name=(name)
|
data/lib/ransack/nodes/value.rb
CHANGED
|
@@ -24,9 +24,11 @@ module Ransack
|
|
|
24
24
|
|
|
25
25
|
def cast(type)
|
|
26
26
|
case type
|
|
27
|
+
when :enum
|
|
28
|
+
value
|
|
27
29
|
when :date
|
|
28
30
|
cast_to_date(value)
|
|
29
|
-
when :datetime, :timestamp, :time, :timestamptz
|
|
31
|
+
when :datetime, :timestamp, :time, :timestamptz, :datetimeoffset
|
|
30
32
|
cast_to_time(value)
|
|
31
33
|
when :boolean
|
|
32
34
|
cast_to_boolean(value)
|
|
@@ -43,14 +45,6 @@ module Ransack
|
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
46
|
-
def cast_array
|
|
47
|
-
if value.is_a?(Array)
|
|
48
|
-
cast_to_date(value)
|
|
49
|
-
else
|
|
50
|
-
value
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
48
|
def cast_to_date(val)
|
|
55
49
|
if val.respond_to?(:to_date)
|
|
56
50
|
val.to_date rescue nil
|
data/lib/ransack/predicate.rb
CHANGED
|
@@ -3,6 +3,17 @@ module Ransack
|
|
|
3
3
|
attr_reader :name, :arel_predicate, :type, :formatter, :validator,
|
|
4
4
|
:compound, :wants_array, :case_insensitive
|
|
5
5
|
|
|
6
|
+
# Consulted at search time rather than captured at predicate-definition
|
|
7
|
+
# time, so that `Ransack.options[:ignore_blank_values]` set in an
|
|
8
|
+
# initializer applies to the predicates registered before it ran.
|
|
9
|
+
DEFAULT_VALIDATOR = lambda do |v|
|
|
10
|
+
if Ransack.options[:ignore_blank_values]
|
|
11
|
+
v.respond_to?(:empty?) ? !v.empty? : !v.nil?
|
|
12
|
+
else
|
|
13
|
+
!v.nil?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
6
17
|
class << self
|
|
7
18
|
|
|
8
19
|
def names
|
|
@@ -37,8 +48,7 @@ module Ransack
|
|
|
37
48
|
@arel_predicate = opts[:arel_predicate]
|
|
38
49
|
@type = opts[:type]
|
|
39
50
|
@formatter = opts[:formatter]
|
|
40
|
-
@validator = opts[:validator] ||
|
|
41
|
-
lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
|
|
51
|
+
@validator = opts[:validator] || DEFAULT_VALIDATOR
|
|
42
52
|
@compound = opts[:compound]
|
|
43
53
|
@wants_array = opts.fetch(:wants_array,
|
|
44
54
|
@compound || Constants::IN_NOT_IN.include?(@arel_predicate))
|
|
@@ -64,7 +74,18 @@ module Ransack
|
|
|
64
74
|
end
|
|
65
75
|
|
|
66
76
|
def validate(vals, type = @type)
|
|
67
|
-
|
|
77
|
+
# An explicitly empty array is a meaningful filter (matching nothing)
|
|
78
|
+
# rather than an absent one, but only when blank values are not ignored.
|
|
79
|
+
return true if vals.empty? && wants_array &&
|
|
80
|
+
!Ransack.options[:ignore_blank_values]
|
|
81
|
+
|
|
82
|
+
# When blank values are meaningful, validate the value as given. Casting
|
|
83
|
+
# first would turn '' into nil for an integer or boolean column and the
|
|
84
|
+
# explicit blank would be dropped — leaving no condition at all.
|
|
85
|
+
vals.any? do |v|
|
|
86
|
+
value = type && Ransack.options[:ignore_blank_values] ? v.cast(type) : v.value
|
|
87
|
+
validator.call(value)
|
|
88
|
+
end
|
|
68
89
|
end
|
|
69
90
|
|
|
70
91
|
def negative?
|
data/lib/ransack/search.rb
CHANGED
|
@@ -24,14 +24,19 @@ module Ransack
|
|
|
24
24
|
strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
|
|
25
25
|
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
26
26
|
if params.is_a? Hash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
params
|
|
27
|
+
# deep_transform_values rebuilds every nested hash and array, which
|
|
28
|
+
# also gives the pruning below a private copy to edit — the caller's
|
|
29
|
+
# params come back untouched. Values nested inside `g:` groupings and
|
|
30
|
+
# `c:` conditions are stripped too, not just the top level.
|
|
31
|
+
params = params.deep_transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
|
|
32
|
+
params.delete_if { |_k, v| blank_condition_value?(v) }
|
|
33
|
+
prune_blank_advanced_conditions!(params)
|
|
30
34
|
else
|
|
31
35
|
params = {}
|
|
32
36
|
end
|
|
33
37
|
@context = options[:context] || Context.for(object, options)
|
|
34
38
|
@context.auth_object = options[:auth_object]
|
|
39
|
+
@context.ignore_unknown_conditions = options[:ignore_unknown_conditions]
|
|
35
40
|
@base = Nodes::Grouping.new(
|
|
36
41
|
@context, options[:grouping] || Constants::AND
|
|
37
42
|
)
|
|
@@ -132,11 +137,7 @@ module Ransack
|
|
|
132
137
|
private
|
|
133
138
|
|
|
134
139
|
def add_scope(key, args)
|
|
135
|
-
sanitized_args =
|
|
136
|
-
sanitized_scope_args(args)
|
|
137
|
-
else
|
|
138
|
-
args
|
|
139
|
-
end
|
|
140
|
+
sanitized_args = @context.sanitize_scope_args(key, args)
|
|
140
141
|
|
|
141
142
|
if @context.scope_arity(key) == 1
|
|
142
143
|
@scope_args[key] = args.is_a?(Array) ? args[0] : args
|
|
@@ -146,20 +147,6 @@ module Ransack
|
|
|
146
147
|
@context.chain_scope(key, sanitized_args)
|
|
147
148
|
end
|
|
148
149
|
|
|
149
|
-
def sanitized_scope_args(args)
|
|
150
|
-
if args.is_a?(Array)
|
|
151
|
-
args = args.map(&method(:sanitized_scope_args))
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
if Constants::TRUE_VALUES.include? args
|
|
155
|
-
true
|
|
156
|
-
elsif Constants::FALSE_VALUES.include? args
|
|
157
|
-
false
|
|
158
|
-
else
|
|
159
|
-
args
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
150
|
def collapse_multiparameter_attributes!(attrs)
|
|
164
151
|
attrs.keys.each do |k|
|
|
165
152
|
if k.include?(Constants::LEFT_PARENTHESIS)
|
|
@@ -191,5 +178,61 @@ module Ransack
|
|
|
191
178
|
attrs
|
|
192
179
|
end
|
|
193
180
|
|
|
181
|
+
# True when a condition's value should be dropped before building. With
|
|
182
|
+
# `ignore_blank_values` on (the default) a blank value means "this form
|
|
183
|
+
# field was left empty"; with it off, only nil is treated that way and a
|
|
184
|
+
# blank value is a value to search for. `false` is always a real value, and
|
|
185
|
+
# an explicit nil inside an array is kept so `name_in: [nil]` still reaches
|
|
186
|
+
# the query. The `c:` pruning below shares this, so it follows the option.
|
|
187
|
+
def blank_condition_value?(value)
|
|
188
|
+
if Ransack.options[:ignore_blank_values]
|
|
189
|
+
[*value].all? { |i| i.blank? && i != false && !i.nil? }
|
|
190
|
+
else
|
|
191
|
+
value.nil? || (value.is_a?(Array) && !value.empty? && value.all?(&:nil?))
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# The low-level `c:` API nests its values a level deeper than the shorthand
|
|
196
|
+
# form, so the filter above never sees them. Left in place, a condition with
|
|
197
|
+
# an empty value still builds its attribute and contributes a join, giving a
|
|
198
|
+
# LEFT OUTER JOIN with no WHERE clause to go with it.
|
|
199
|
+
def prune_blank_advanced_conditions!(node)
|
|
200
|
+
return unless node.is_a?(Hash)
|
|
201
|
+
|
|
202
|
+
conditions = fetch_either(node, :c, :conditions)
|
|
203
|
+
case conditions
|
|
204
|
+
when Array then conditions.delete_if { |c| blank_advanced_condition?(c) }
|
|
205
|
+
when Hash then conditions.delete_if { |_k, c| blank_advanced_condition?(c) }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Groupings nest to any depth and carry their own conditions, so descend
|
|
209
|
+
# into each of them too.
|
|
210
|
+
groupings = fetch_either(node, :g, :groupings)
|
|
211
|
+
groupings = groupings.values if groupings.is_a?(Hash)
|
|
212
|
+
Array(groupings).each { |grouping| prune_blank_advanced_conditions!(grouping) }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Params are not yet indifferent-access here, so look under both spellings
|
|
216
|
+
# of a key and both its short and long forms.
|
|
217
|
+
def fetch_either(hash, short, long)
|
|
218
|
+
hash[short] || hash[short.to_s] || hash[long] || hash[long.to_s]
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def blank_advanced_condition?(condition)
|
|
222
|
+
return false unless condition.is_a?(Hash)
|
|
223
|
+
|
|
224
|
+
values = condition[:v] || condition['v']
|
|
225
|
+
|
|
226
|
+
case values
|
|
227
|
+
when Array then values.all? { |v| blank_condition_value?(unwrap_value(v)) }
|
|
228
|
+
when Hash then values.all? { |_k, v| blank_condition_value?(unwrap_value(v)) }
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Values in the `c:` API may be given bare or wrapped in a `{ value: ... }`
|
|
233
|
+
# envelope, the same two forms `Condition#values=` accepts.
|
|
234
|
+
def unwrap_value(value)
|
|
235
|
+
value.is_a?(Hash) ? (value[:value] || value['value']) : value
|
|
236
|
+
end
|
|
194
237
|
end
|
|
195
238
|
end
|
data/lib/ransack/version.rb
CHANGED
data/lib/ransack.rb
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
require 'active_support/dependencies/autoload'
|
|
2
2
|
require 'active_support/deprecation'
|
|
3
|
-
require 'active_support/
|
|
4
|
-
|
|
5
|
-
if ::ActiveSupport.version >= ::Gem::Version.new("7.1")
|
|
6
|
-
require 'active_support/deprecator'
|
|
7
|
-
end
|
|
3
|
+
require 'active_support/deprecator'
|
|
8
4
|
|
|
9
5
|
require 'active_support/core_ext'
|
|
10
6
|
require 'ransack/configuration'
|
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: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ernie Miller
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
- David Rodríguez
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: activerecord
|
|
@@ -19,28 +19,28 @@ dependencies:
|
|
|
19
19
|
requirements:
|
|
20
20
|
- - ">="
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: '7.
|
|
22
|
+
version: '7.2'
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '7.
|
|
29
|
+
version: '7.2'
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
|
31
31
|
name: activesupport
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
|
33
33
|
requirements:
|
|
34
34
|
- - ">="
|
|
35
35
|
- !ruby/object:Gem::Version
|
|
36
|
-
version: '7.
|
|
36
|
+
version: '7.2'
|
|
37
37
|
type: :runtime
|
|
38
38
|
prerelease: false
|
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
40
|
requirements:
|
|
41
41
|
- - ">="
|
|
42
42
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: '7.
|
|
43
|
+
version: '7.2'
|
|
44
44
|
- !ruby/object:Gem::Dependency
|
|
45
45
|
name: i18n
|
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -130,32 +130,6 @@ files:
|
|
|
130
130
|
- lib/ransack/translate.rb
|
|
131
131
|
- lib/ransack/version.rb
|
|
132
132
|
- lib/ransack/visitor.rb
|
|
133
|
-
- spec/blueprints/articles.rb
|
|
134
|
-
- spec/blueprints/comments.rb
|
|
135
|
-
- spec/blueprints/notes.rb
|
|
136
|
-
- spec/blueprints/people.rb
|
|
137
|
-
- spec/blueprints/tags.rb
|
|
138
|
-
- spec/console.rb
|
|
139
|
-
- spec/helpers/polyamorous_helper.rb
|
|
140
|
-
- spec/helpers/ransack_helper.rb
|
|
141
|
-
- spec/polyamorous/activerecord_compatibility_spec.rb
|
|
142
|
-
- spec/polyamorous/join_association_spec.rb
|
|
143
|
-
- spec/polyamorous/join_dependency_spec.rb
|
|
144
|
-
- spec/polyamorous/join_spec.rb
|
|
145
|
-
- spec/ransack/adapters/active_record/base_spec.rb
|
|
146
|
-
- spec/ransack/adapters/active_record/context_spec.rb
|
|
147
|
-
- spec/ransack/configuration_spec.rb
|
|
148
|
-
- spec/ransack/helpers/form_builder_spec.rb
|
|
149
|
-
- spec/ransack/helpers/form_helper_spec.rb
|
|
150
|
-
- spec/ransack/nodes/condition_spec.rb
|
|
151
|
-
- spec/ransack/nodes/grouping_spec.rb
|
|
152
|
-
- spec/ransack/nodes/value_spec.rb
|
|
153
|
-
- spec/ransack/predicate_spec.rb
|
|
154
|
-
- spec/ransack/search_spec.rb
|
|
155
|
-
- spec/ransack/translate_spec.rb
|
|
156
|
-
- spec/spec_helper.rb
|
|
157
|
-
- spec/support/en.yml
|
|
158
|
-
- spec/support/schema.rb
|
|
159
133
|
homepage: https://github.com/activerecord-hackery/ransack
|
|
160
134
|
licenses:
|
|
161
135
|
- MIT
|
|
@@ -168,40 +142,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
168
142
|
requirements:
|
|
169
143
|
- - ">="
|
|
170
144
|
- !ruby/object:Gem::Version
|
|
171
|
-
version: '3.
|
|
145
|
+
version: '3.1'
|
|
172
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
147
|
requirements:
|
|
174
148
|
- - ">="
|
|
175
149
|
- !ruby/object:Gem::Version
|
|
176
150
|
version: '0'
|
|
177
151
|
requirements: []
|
|
178
|
-
rubygems_version: 3.6.
|
|
152
|
+
rubygems_version: 3.6.9
|
|
179
153
|
specification_version: 4
|
|
180
154
|
summary: Object-based searching for Active Record.
|
|
181
|
-
test_files:
|
|
182
|
-
- spec/blueprints/articles.rb
|
|
183
|
-
- spec/blueprints/comments.rb
|
|
184
|
-
- spec/blueprints/notes.rb
|
|
185
|
-
- spec/blueprints/people.rb
|
|
186
|
-
- spec/blueprints/tags.rb
|
|
187
|
-
- spec/console.rb
|
|
188
|
-
- spec/helpers/polyamorous_helper.rb
|
|
189
|
-
- spec/helpers/ransack_helper.rb
|
|
190
|
-
- spec/polyamorous/activerecord_compatibility_spec.rb
|
|
191
|
-
- spec/polyamorous/join_association_spec.rb
|
|
192
|
-
- spec/polyamorous/join_dependency_spec.rb
|
|
193
|
-
- spec/polyamorous/join_spec.rb
|
|
194
|
-
- spec/ransack/adapters/active_record/base_spec.rb
|
|
195
|
-
- spec/ransack/adapters/active_record/context_spec.rb
|
|
196
|
-
- spec/ransack/configuration_spec.rb
|
|
197
|
-
- spec/ransack/helpers/form_builder_spec.rb
|
|
198
|
-
- spec/ransack/helpers/form_helper_spec.rb
|
|
199
|
-
- spec/ransack/nodes/condition_spec.rb
|
|
200
|
-
- spec/ransack/nodes/grouping_spec.rb
|
|
201
|
-
- spec/ransack/nodes/value_spec.rb
|
|
202
|
-
- spec/ransack/predicate_spec.rb
|
|
203
|
-
- spec/ransack/search_spec.rb
|
|
204
|
-
- spec/ransack/translate_spec.rb
|
|
205
|
-
- spec/spec_helper.rb
|
|
206
|
-
- spec/support/en.yml
|
|
207
|
-
- spec/support/schema.rb
|
|
155
|
+
test_files: []
|
data/spec/blueprints/articles.rb
DELETED
data/spec/blueprints/comments.rb
DELETED
data/spec/blueprints/notes.rb
DELETED
data/spec/blueprints/people.rb
DELETED
data/spec/blueprints/tags.rb
DELETED
data/spec/console.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
Bundler.setup
|
|
2
|
-
require 'machinist/active_record'
|
|
3
|
-
require 'sham'
|
|
4
|
-
require 'faker'
|
|
5
|
-
require 'ransack'
|
|
6
|
-
|
|
7
|
-
Dir[File.expand_path('../../spec/{helpers,support,blueprints}/*.rb', __FILE__)]
|
|
8
|
-
.each do |f|
|
|
9
|
-
require f
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
Sham.define do
|
|
13
|
-
name { Faker::Name.name }
|
|
14
|
-
title { Faker::Lorem.sentence }
|
|
15
|
-
body { Faker::Lorem.paragraph }
|
|
16
|
-
salary { |index| 30000 + (index * 1000) }
|
|
17
|
-
tag_name { Faker::Lorem.words(number: 3).join(' ') }
|
|
18
|
-
note { Faker::Lorem.words(number: 7).join(' ') }
|
|
19
|
-
only_admin { Faker::Lorem.words(number: 3).join(' ') }
|
|
20
|
-
only_search { Faker::Lorem.words(number: 3).join(' ') }
|
|
21
|
-
only_sort { Faker::Lorem.words(number: 3).join(' ') }
|
|
22
|
-
notable_id { |id| id }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
Schema.create
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module PolyamorousHelper
|
|
2
|
-
def new_join_association(reflection, children, klass)
|
|
3
|
-
Polyamorous::JoinAssociation.new reflection, children, klass
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
def new_join_dependency(klass, associations = {})
|
|
7
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, Polyamorous::InnerJoin
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def new_join(name, type = Polyamorous::InnerJoin, klass = nil)
|
|
11
|
-
Polyamorous::Join.new name, type, klass
|
|
12
|
-
end
|
|
13
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Polyamorous
|
|
4
|
-
describe "ActiveRecord Compatibility" do
|
|
5
|
-
it 'works with self joins and includes' do
|
|
6
|
-
trade_account = Account.create!
|
|
7
|
-
Account.create!(trade_account: trade_account)
|
|
8
|
-
|
|
9
|
-
accounts = Account.joins(:trade_account).includes(:trade_account, :agent_account)
|
|
10
|
-
account = accounts.first
|
|
11
|
-
|
|
12
|
-
expect(account.agent_account).to be_nil
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Polyamorous
|
|
4
|
-
describe JoinAssociation do
|
|
5
|
-
let(:join_dependency) { new_join_dependency Note, {} }
|
|
6
|
-
let(:reflection) { Note.reflect_on_association(:notable) }
|
|
7
|
-
let(:parent) { join_dependency.send(:join_root) }
|
|
8
|
-
let(:join_association) {
|
|
9
|
-
new_join_association(reflection, parent.children, Article)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
subject { new_join_association(reflection, parent.children, Person) }
|
|
13
|
-
|
|
14
|
-
it 'leaves the original reflection intact for thread safety' do
|
|
15
|
-
reflection.instance_variable_set(:@klass, Article)
|
|
16
|
-
join_association
|
|
17
|
-
.swapping_reflection_klass(reflection, Person) do |new_reflection|
|
|
18
|
-
expect(new_reflection.options).not_to equal reflection.options
|
|
19
|
-
expect(new_reflection.options).not_to have_key(:polymorphic)
|
|
20
|
-
expect(new_reflection.klass).to eq(Person)
|
|
21
|
-
expect(reflection.klass).to eq(Article)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'sets the polymorphic option to true after initializing' do
|
|
26
|
-
expect(join_association.reflection.options[:polymorphic]).to be true
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Polyamorous
|
|
4
|
-
describe JoinDependency do
|
|
5
|
-
context 'with symbol joins' do
|
|
6
|
-
subject { new_join_dependency Person, articles: :comments }
|
|
7
|
-
|
|
8
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
9
|
-
.to eq(2) }
|
|
10
|
-
specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
|
|
11
|
-
.to eq [Polyamorous::InnerJoin] }
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
context 'with has_many :through association' do
|
|
15
|
-
subject { new_join_dependency Person, :authored_article_comments }
|
|
16
|
-
|
|
17
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
18
|
-
.to eq 1 }
|
|
19
|
-
specify { expect(subject.send(:join_root).drop(1).first.table_name)
|
|
20
|
-
.to eq 'comments' }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context 'with outer join' do
|
|
24
|
-
subject { new_join_dependency Person, new_join(:articles, :outer) }
|
|
25
|
-
|
|
26
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
27
|
-
.to eq 1 }
|
|
28
|
-
specify { expect(subject.send(:join_root).drop(1).first.join_type)
|
|
29
|
-
.to eq Polyamorous::OuterJoin }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
context 'with nested outer joins' do
|
|
33
|
-
subject { new_join_dependency Person,
|
|
34
|
-
new_join(:articles, :outer) => new_join(:comments, :outer) }
|
|
35
|
-
|
|
36
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
37
|
-
.to eq 2 }
|
|
38
|
-
specify { expect(subject.send(:join_root).drop(1).map(&:join_type))
|
|
39
|
-
.to eq [Polyamorous::OuterJoin, Polyamorous::OuterJoin] }
|
|
40
|
-
specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
|
|
41
|
-
.to eq [Polyamorous::OuterJoin] }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
context 'with polymorphic belongs_to join' do
|
|
45
|
-
subject { new_join_dependency Note, new_join(:notable, :inner, Person) }
|
|
46
|
-
|
|
47
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
48
|
-
.to eq 1 }
|
|
49
|
-
specify { expect(subject.send(:join_root).drop(1).first.join_type)
|
|
50
|
-
.to eq Polyamorous::InnerJoin }
|
|
51
|
-
specify { expect(subject.send(:join_root).drop(1).first.table_name)
|
|
52
|
-
.to eq 'people' }
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context 'with polymorphic belongs_to join and nested symbol join' do
|
|
56
|
-
subject { new_join_dependency Note,
|
|
57
|
-
new_join(:notable, :inner, Person) => :comments }
|
|
58
|
-
|
|
59
|
-
specify { expect(subject.send(:join_root).drop(1).size)
|
|
60
|
-
.to eq 2 }
|
|
61
|
-
specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
|
|
62
|
-
.to eq [Polyamorous::InnerJoin] }
|
|
63
|
-
specify { expect(subject.send(:join_root).drop(1).first.table_name)
|
|
64
|
-
.to eq 'people' }
|
|
65
|
-
specify { expect(subject.send(:join_root).drop(1)[1].table_name)
|
|
66
|
-
.to eq 'comments' }
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
context 'with polymorphic belongs_to join and nested join' do
|
|
70
|
-
subject { new_join_dependency Note,
|
|
71
|
-
new_join(:notable, :outer, Person) => :comments }
|
|
72
|
-
specify { expect(subject.send(:join_root).drop(1).size).to eq 2 }
|
|
73
|
-
specify { expect(subject.send(:join_root).drop(1).map(&:join_type)).to eq [Polyamorous::OuterJoin, Polyamorous::InnerJoin] }
|
|
74
|
-
specify { expect(subject.send(:join_root).drop(1).first.table_name)
|
|
75
|
-
.to eq 'people' }
|
|
76
|
-
specify { expect(subject.send(:join_root).drop(1)[1].table_name)
|
|
77
|
-
.to eq 'comments' }
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Polyamorous
|
|
4
|
-
describe Join do
|
|
5
|
-
it 'is a tree node' do
|
|
6
|
-
join = new_join(:articles, :outer)
|
|
7
|
-
expect(join).to be_kind_of(TreeNode)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it 'can be added to a tree' do
|
|
11
|
-
join = new_join(:articles, :outer)
|
|
12
|
-
|
|
13
|
-
tree_hash = {}
|
|
14
|
-
join.add_to_tree(tree_hash)
|
|
15
|
-
|
|
16
|
-
expect(tree_hash[join]).to be {}
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|