giga-pure-kit 0.0.1
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.
Potentially problematic release.
This version of giga-pure-kit might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/giga-pure-kit.gemspec +12 -0
- data/ransack-4.4.1/LICENSE +20 -0
- data/ransack-4.4.1/README.md +101 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association.rb +218 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_dependency.rb +102 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/reflection.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/join.rb +70 -0
- data/ransack-4.4.1/lib/polyamorous/polyamorous.rb +27 -0
- data/ransack-4.4.1/lib/polyamorous/swapping_reflection_class.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/tree_node.rb +7 -0
- data/ransack-4.4.1/lib/ransack/active_record.rb +14 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/base.rb +152 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/context.rb +373 -0
- data/ransack-4.4.1/lib/ransack/configuration.rb +209 -0
- data/ransack-4.4.1/lib/ransack/constants.rb +176 -0
- data/ransack-4.4.1/lib/ransack/context.rb +190 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_builder.rb +277 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_helper.rb +311 -0
- data/ransack-4.4.1/lib/ransack/helpers.rb +2 -0
- data/ransack-4.4.1/lib/ransack/invalid_search_error.rb +3 -0
- data/ransack-4.4.1/lib/ransack/locale/ar.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/az.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/bg.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ca.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/cs.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/da.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/de.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/el.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/en.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/es.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fa.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fi.yml +71 -0
- data/ransack-4.4.1/lib/ransack/locale/fr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/hu.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/id.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/it.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ja.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ko.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/nl.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/pt-BR.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ro.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ru.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sk.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sv.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/tr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/uk.yml +72 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-CN.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-TW.yml +70 -0
- data/ransack-4.4.1/lib/ransack/naming.rb +58 -0
- data/ransack-4.4.1/lib/ransack/nodes/attribute.rb +59 -0
- data/ransack-4.4.1/lib/ransack/nodes/bindable.rb +52 -0
- data/ransack-4.4.1/lib/ransack/nodes/condition.rb +399 -0
- data/ransack-4.4.1/lib/ransack/nodes/grouping.rb +206 -0
- data/ransack-4.4.1/lib/ransack/nodes/node.rb +34 -0
- data/ransack-4.4.1/lib/ransack/nodes/sort.rb +54 -0
- data/ransack-4.4.1/lib/ransack/nodes/value.rb +115 -0
- data/ransack-4.4.1/lib/ransack/predicate.rb +75 -0
- data/ransack-4.4.1/lib/ransack/ransacker.rb +24 -0
- data/ransack-4.4.1/lib/ransack/search.rb +195 -0
- data/ransack-4.4.1/lib/ransack/translate.rb +156 -0
- data/ransack-4.4.1/lib/ransack/version.rb +3 -0
- data/ransack-4.4.1/lib/ransack/visitor.rb +87 -0
- data/ransack-4.4.1/lib/ransack.rb +33 -0
- data/ransack-4.4.1/spec/console.rb +13 -0
- data/ransack-4.4.1/spec/factories/articles.rb +7 -0
- data/ransack-4.4.1/spec/factories/comments.rb +7 -0
- data/ransack-4.4.1/spec/factories/notes.rb +13 -0
- data/ransack-4.4.1/spec/factories/people.rb +10 -0
- data/ransack-4.4.1/spec/factories/tags.rb +5 -0
- data/ransack-4.4.1/spec/helpers/polyamorous_helper.rb +13 -0
- data/ransack-4.4.1/spec/helpers/ransack_helper.rb +9 -0
- data/ransack-4.4.1/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/ransack-4.4.1/spec/polyamorous/join_association_spec.rb +29 -0
- data/ransack-4.4.1/spec/polyamorous/join_dependency_spec.rb +80 -0
- data/ransack-4.4.1/spec/polyamorous/join_spec.rb +19 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/base_spec.rb +943 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/context_spec.rb +219 -0
- data/ransack-4.4.1/spec/ransack/configuration_spec.rb +201 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_builder_spec.rb +169 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_helper_spec.rb +1075 -0
- data/ransack-4.4.1/spec/ransack/invalid_search_error_spec.rb +27 -0
- data/ransack-4.4.1/spec/ransack/nodes/condition_spec.rb +333 -0
- data/ransack-4.4.1/spec/ransack/nodes/grouping_spec.rb +111 -0
- data/ransack-4.4.1/spec/ransack/nodes/value_spec.rb +126 -0
- data/ransack-4.4.1/spec/ransack/predicate_spec.rb +504 -0
- data/ransack-4.4.1/spec/ransack/ransacker_spec.rb +69 -0
- data/ransack-4.4.1/spec/ransack/search_spec.rb +821 -0
- data/ransack-4.4.1/spec/ransack/translate_spec.rb +16 -0
- data/ransack-4.4.1/spec/spec_helper.rb +52 -0
- data/ransack-4.4.1/spec/support/en.yml +18 -0
- data/ransack-4.4.1/spec/support/schema.rb +419 -0
- metadata +133 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Nodes
|
|
3
|
+
class Grouping < Node
|
|
4
|
+
attr_reader :conditions
|
|
5
|
+
attr_accessor :combinator
|
|
6
|
+
alias :m :combinator
|
|
7
|
+
alias :m= :combinator=
|
|
8
|
+
|
|
9
|
+
i18n_word :condition, :and, :or
|
|
10
|
+
i18n_alias c: :condition, n: :and, o: :or
|
|
11
|
+
|
|
12
|
+
delegate :each, to: :values
|
|
13
|
+
|
|
14
|
+
def initialize(context, combinator = nil)
|
|
15
|
+
super(context)
|
|
16
|
+
self.combinator = combinator.to_s if combinator
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def persisted?
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def translate(key, options = {})
|
|
24
|
+
super or Translate.attribute(
|
|
25
|
+
key.to_s, options.merge(context: context)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def conditions
|
|
30
|
+
@conditions ||= []
|
|
31
|
+
end
|
|
32
|
+
alias :c :conditions
|
|
33
|
+
|
|
34
|
+
def conditions=(conditions)
|
|
35
|
+
case conditions
|
|
36
|
+
when Array
|
|
37
|
+
conditions.each do |attrs|
|
|
38
|
+
condition = Condition.new(@context).build(attrs)
|
|
39
|
+
self.conditions << condition if condition.valid?
|
|
40
|
+
end
|
|
41
|
+
when Hash
|
|
42
|
+
conditions.each do |index, attrs|
|
|
43
|
+
condition = Condition.new(@context).build(attrs)
|
|
44
|
+
self.conditions << condition if condition.valid?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
remove_duplicate_conditions!
|
|
48
|
+
end
|
|
49
|
+
alias :c= :conditions=
|
|
50
|
+
|
|
51
|
+
def [](key)
|
|
52
|
+
conditions.detect { |c| c.key == key.to_s }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def []=(key, value)
|
|
56
|
+
conditions.reject! { |c| c.key == key.to_s && c&.value == value&.value }
|
|
57
|
+
self.conditions << value
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def values
|
|
61
|
+
conditions + groupings
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def respond_to?(method_id)
|
|
65
|
+
super or begin
|
|
66
|
+
method_name = method_id.to_s
|
|
67
|
+
attribute_method?(method_name) ? true : false
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def build_condition(opts = {})
|
|
72
|
+
new_condition(opts).tap do |condition|
|
|
73
|
+
self.conditions << condition
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def new_condition(opts = {})
|
|
78
|
+
attrs = opts[:attributes] || 1
|
|
79
|
+
vals = opts[:values] || 1
|
|
80
|
+
condition = Condition.new(@context)
|
|
81
|
+
attrs.times { condition.build_attribute }
|
|
82
|
+
vals.times { condition.build_value }
|
|
83
|
+
condition
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def groupings
|
|
87
|
+
@groupings ||= []
|
|
88
|
+
end
|
|
89
|
+
alias :g :groupings
|
|
90
|
+
|
|
91
|
+
def groupings=(groupings)
|
|
92
|
+
case groupings
|
|
93
|
+
when Array
|
|
94
|
+
groupings.each do |attrs|
|
|
95
|
+
grouping_object = new_grouping(attrs)
|
|
96
|
+
self.groupings << grouping_object if grouping_object.values.any?
|
|
97
|
+
end
|
|
98
|
+
when Hash
|
|
99
|
+
groupings.each do |index, attrs|
|
|
100
|
+
grouping_object = new_grouping(attrs)
|
|
101
|
+
self.groupings << grouping_object if grouping_object.values.any?
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
raise ArgumentError,
|
|
105
|
+
"Invalid argument (#{groupings.class}) supplied to groupings="
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
alias :g= :groupings=
|
|
109
|
+
|
|
110
|
+
def method_missing(method_id, *args)
|
|
111
|
+
method_name = method_id.to_s.dup
|
|
112
|
+
writer = method_name.sub!(/\=$/, ''.freeze)
|
|
113
|
+
if attribute_method?(method_name)
|
|
114
|
+
if writer
|
|
115
|
+
write_attribute(method_name, *args)
|
|
116
|
+
else
|
|
117
|
+
read_attribute(method_name)
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
super
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def attribute_method?(name)
|
|
125
|
+
stripped_name = strip_predicate_and_index(name)
|
|
126
|
+
return true if @context.attribute_method?(stripped_name) ||
|
|
127
|
+
@context.attribute_method?(name)
|
|
128
|
+
case stripped_name
|
|
129
|
+
when /^(g|c|m|groupings|conditions|combinator)=?$/
|
|
130
|
+
true
|
|
131
|
+
else
|
|
132
|
+
stripped_name
|
|
133
|
+
.split(/_and_|_or_/)
|
|
134
|
+
.none? { |n| !@context.attribute_method?(n) }
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def build_grouping(params = {})
|
|
139
|
+
params ||= {}
|
|
140
|
+
new_grouping(params).tap do |new_grouping|
|
|
141
|
+
self.groupings << new_grouping
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def new_grouping(params = {})
|
|
146
|
+
Grouping.new(@context).build(params)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def build(params)
|
|
150
|
+
params.with_indifferent_access.each do |key, value|
|
|
151
|
+
case key
|
|
152
|
+
when /^(g|c|m)$/
|
|
153
|
+
self.send("#{key}=", value)
|
|
154
|
+
else
|
|
155
|
+
write_attribute(key.to_s, value)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
self
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def inspect
|
|
162
|
+
data = [
|
|
163
|
+
['conditions'.freeze, conditions], [Constants::COMBINATOR, combinator]
|
|
164
|
+
]
|
|
165
|
+
.reject { |e| e[1].blank? }
|
|
166
|
+
.map { |v| "#{v[0]}: #{v[1]}" }
|
|
167
|
+
.join(', '.freeze)
|
|
168
|
+
"Grouping <#{data}>"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
|
|
173
|
+
def write_attribute(name, val)
|
|
174
|
+
# TODO: Methods
|
|
175
|
+
if condition = Condition.extract(@context, name, val)
|
|
176
|
+
self[name] = condition
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def read_attribute(name)
|
|
181
|
+
if self[name].respond_to?(:value)
|
|
182
|
+
self[name].value
|
|
183
|
+
else
|
|
184
|
+
self[name]
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def strip_predicate_and_index(str)
|
|
189
|
+
string = str[/(.+?)\(/, 1] || str.dup
|
|
190
|
+
Predicate.detect_and_strip_from_string!(string)
|
|
191
|
+
string
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def remove_duplicate_conditions!
|
|
195
|
+
# If self.conditions.uniq! is called without passing a block, then
|
|
196
|
+
# conditions differing only by ransacker_args within attributes are
|
|
197
|
+
# wrongly considered equal and are removed.
|
|
198
|
+
self.conditions.uniq! do |c|
|
|
199
|
+
c.attributes.map { |a| [a.name, a.ransacker_args] }.flatten +
|
|
200
|
+
[c.predicate.name] +
|
|
201
|
+
c.values.map { |v| v.value }
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Nodes
|
|
3
|
+
class Node
|
|
4
|
+
attr_reader :context
|
|
5
|
+
delegate :contextualize, to: :context
|
|
6
|
+
class_attribute :i18n_words
|
|
7
|
+
class_attribute :i18n_aliases
|
|
8
|
+
self.i18n_words = []
|
|
9
|
+
self.i18n_aliases = {}
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
def i18n_word(*args)
|
|
13
|
+
self.i18n_words += args.map(&:to_s)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def i18n_alias(opts = {})
|
|
17
|
+
self.i18n_aliases.merge! Hash[opts.map { |k, v| [k.to_s, v.to_s] }]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(context)
|
|
22
|
+
@context = context
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def translate(key, options = {})
|
|
26
|
+
key = i18n_aliases[key.to_s] if i18n_aliases.has_key?(key.to_s)
|
|
27
|
+
if i18n_words.include?(key.to_s)
|
|
28
|
+
Translate.word(key)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Nodes
|
|
3
|
+
class Sort < Node
|
|
4
|
+
include Bindable
|
|
5
|
+
|
|
6
|
+
attr_reader :name, :dir, :ransacker_args
|
|
7
|
+
i18n_word :asc, :desc
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def extract(context, str)
|
|
11
|
+
return if str.blank?
|
|
12
|
+
attr, direction = str.split(/\s+/, 2)
|
|
13
|
+
self.new(context).build(name: attr, dir: direction)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build(params)
|
|
18
|
+
params.with_indifferent_access.each do |key, value|
|
|
19
|
+
if key.match(/^(name|dir|ransacker_args)$/)
|
|
20
|
+
self.send("#{key}=", value)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def valid?
|
|
28
|
+
bound? && attr &&
|
|
29
|
+
context.klassify(parent).ransortable_attributes(context.auth_object)
|
|
30
|
+
.include?(attr_name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def name=(name)
|
|
34
|
+
@name = context.ransackable_alias(name) || name
|
|
35
|
+
context.bind(self, @name)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def dir=(dir)
|
|
39
|
+
dir = dir.downcase if dir
|
|
40
|
+
@dir =
|
|
41
|
+
if dir == 'asc'.freeze || dir == 'desc'.freeze
|
|
42
|
+
dir
|
|
43
|
+
else
|
|
44
|
+
'asc'.freeze
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def ransacker_args=(ransack_args)
|
|
49
|
+
@ransacker_args = ransack_args
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Nodes
|
|
3
|
+
class Value < Node
|
|
4
|
+
attr_accessor :value
|
|
5
|
+
delegate :present?, :blank?, to: :value
|
|
6
|
+
|
|
7
|
+
def initialize(context, value = nil)
|
|
8
|
+
super(context)
|
|
9
|
+
@value = value
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def persisted?
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def eql?(other)
|
|
17
|
+
self.class == other.class && self.value == other.value
|
|
18
|
+
end
|
|
19
|
+
alias :== :eql?
|
|
20
|
+
|
|
21
|
+
def hash
|
|
22
|
+
value.hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def cast(type)
|
|
26
|
+
case type
|
|
27
|
+
when :date
|
|
28
|
+
cast_to_date(value)
|
|
29
|
+
when :datetime, :timestamp, :time, :timestamptz
|
|
30
|
+
cast_to_time(value)
|
|
31
|
+
when :boolean
|
|
32
|
+
cast_to_boolean(value)
|
|
33
|
+
when :integer
|
|
34
|
+
cast_to_integer(value)
|
|
35
|
+
when :float
|
|
36
|
+
cast_to_float(value)
|
|
37
|
+
when :decimal
|
|
38
|
+
cast_to_decimal(value)
|
|
39
|
+
when :money
|
|
40
|
+
cast_to_money(value)
|
|
41
|
+
else
|
|
42
|
+
cast_to_string(value)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def cast_to_date(val)
|
|
47
|
+
if val.respond_to?(:to_date)
|
|
48
|
+
val.to_date rescue nil
|
|
49
|
+
else
|
|
50
|
+
y, m, d = *[val].flatten
|
|
51
|
+
m ||= 1
|
|
52
|
+
d ||= 1
|
|
53
|
+
Date.new(y, m, d) rescue nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cast_to_time(val)
|
|
58
|
+
if val.is_a?(Array)
|
|
59
|
+
Time.zone.local(*val) rescue nil
|
|
60
|
+
else
|
|
61
|
+
unless val.acts_like?(:time)
|
|
62
|
+
val = val.is_a?(String) ? Time.zone.parse(val) : val.to_time rescue val
|
|
63
|
+
end
|
|
64
|
+
val.in_time_zone rescue nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def cast_to_boolean(val)
|
|
69
|
+
if Constants::TRUE_VALUES.include?(val)
|
|
70
|
+
true
|
|
71
|
+
elsif Constants::FALSE_VALUES.include?(val)
|
|
72
|
+
false
|
|
73
|
+
else
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def cast_to_string(val)
|
|
79
|
+
val.respond_to?(:to_s) ? val.to_s : String.new(val)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def cast_to_integer(val)
|
|
83
|
+
val.respond_to?(:to_i) && !val.blank? ? val.to_i : nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def cast_to_float(val)
|
|
87
|
+
val.blank? ? nil : val.to_f
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def cast_to_decimal(val)
|
|
91
|
+
if val.blank?
|
|
92
|
+
nil
|
|
93
|
+
elsif val.class == BigDecimal
|
|
94
|
+
val
|
|
95
|
+
elsif val.respond_to?(:to_d)
|
|
96
|
+
val.to_d
|
|
97
|
+
else
|
|
98
|
+
val.to_s.to_d
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def cast_to_money(val)
|
|
103
|
+
val.blank? ? nil : val.to_f.to_s
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def inspect
|
|
107
|
+
"Value <#{value}>"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def array_of_arrays?(val)
|
|
111
|
+
Array === val && Array === val.first
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
class Predicate
|
|
3
|
+
attr_reader :name, :arel_predicate, :type, :formatter, :validator,
|
|
4
|
+
:compound, :wants_array, :case_insensitive
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def names
|
|
9
|
+
Ransack.predicates.keys
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def named(name)
|
|
13
|
+
Ransack.predicates[(name || Ransack.options[:default_predicate]).to_s]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def detect_and_strip_from_string!(str)
|
|
17
|
+
detect_from_string str, chomp: true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def detect_from_string(str, chomp: false)
|
|
21
|
+
return unless str
|
|
22
|
+
|
|
23
|
+
Ransack.predicates.sorted_names_with_underscores.each do |predicate, underscored|
|
|
24
|
+
if str.end_with? underscored
|
|
25
|
+
str.chomp! underscored if chomp
|
|
26
|
+
return predicate
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(opts = {})
|
|
36
|
+
@name = opts[:name]
|
|
37
|
+
@arel_predicate = opts[:arel_predicate]
|
|
38
|
+
@type = opts[:type]
|
|
39
|
+
@formatter = opts[:formatter]
|
|
40
|
+
@validator = opts[:validator] ||
|
|
41
|
+
lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
|
|
42
|
+
@compound = opts[:compound]
|
|
43
|
+
@wants_array = opts.fetch(:wants_array,
|
|
44
|
+
@compound || Constants::IN_NOT_IN.include?(@arel_predicate))
|
|
45
|
+
@case_insensitive = opts[:case_insensitive]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def eql?(other)
|
|
49
|
+
self.class == other.class &&
|
|
50
|
+
self.name == other.name
|
|
51
|
+
end
|
|
52
|
+
alias :== :eql?
|
|
53
|
+
|
|
54
|
+
def hash
|
|
55
|
+
name.hash
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def format(val)
|
|
59
|
+
if formatter
|
|
60
|
+
formatter.call(val)
|
|
61
|
+
else
|
|
62
|
+
val
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validate(vals, type = @type)
|
|
67
|
+
vals.any? { |v| validator.call(type ? v.cast(type) : v.value) }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def negative?
|
|
71
|
+
@name.include?("not_".freeze)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
class Ransacker
|
|
3
|
+
|
|
4
|
+
attr_reader :name, :type, :formatter, :args
|
|
5
|
+
|
|
6
|
+
delegate :call, to: :@callable
|
|
7
|
+
|
|
8
|
+
def initialize(klass, name, opts = {}, &block)
|
|
9
|
+
@klass, @name = klass, name
|
|
10
|
+
|
|
11
|
+
@type = opts[:type] || :string
|
|
12
|
+
@args = opts[:args] || [:parent]
|
|
13
|
+
@formatter = opts[:formatter]
|
|
14
|
+
@callable = opts[:callable] || block ||
|
|
15
|
+
(@klass.method(name) if @klass.respond_to?(name)) ||
|
|
16
|
+
proc { |parent| parent.table[name] }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def attr_from(bindable)
|
|
20
|
+
call(*args.map { |arg| bindable.send(arg) })
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
require 'ransack/nodes/bindable'
|
|
2
|
+
require 'ransack/nodes/node'
|
|
3
|
+
require 'ransack/nodes/attribute'
|
|
4
|
+
require 'ransack/nodes/value'
|
|
5
|
+
require 'ransack/nodes/condition'
|
|
6
|
+
require 'ransack/nodes/sort'
|
|
7
|
+
require 'ransack/nodes/grouping'
|
|
8
|
+
require 'ransack/context'
|
|
9
|
+
require 'ransack/naming'
|
|
10
|
+
require 'ransack/invalid_search_error'
|
|
11
|
+
|
|
12
|
+
module Ransack
|
|
13
|
+
class Search
|
|
14
|
+
include Naming
|
|
15
|
+
|
|
16
|
+
attr_reader :base, :context
|
|
17
|
+
|
|
18
|
+
delegate :object, :klass, to: :context
|
|
19
|
+
delegate :new_grouping, :new_condition,
|
|
20
|
+
:build_grouping, :build_condition,
|
|
21
|
+
:translate, to: :base
|
|
22
|
+
|
|
23
|
+
def initialize(object, params = {}, options = {})
|
|
24
|
+
strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
|
|
25
|
+
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
26
|
+
if params.is_a? Hash
|
|
27
|
+
params = params.dup
|
|
28
|
+
params = params.transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
|
|
29
|
+
params.delete_if { |k, v| [*v].all?{ |i| i.blank? && i != false } }
|
|
30
|
+
else
|
|
31
|
+
params = {}
|
|
32
|
+
end
|
|
33
|
+
@context = options[:context] || Context.for(object, options)
|
|
34
|
+
@context.auth_object = options[:auth_object]
|
|
35
|
+
@base = Nodes::Grouping.new(
|
|
36
|
+
@context, options[:grouping] || Constants::AND
|
|
37
|
+
)
|
|
38
|
+
@scope_args = {}
|
|
39
|
+
@sorts ||= []
|
|
40
|
+
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
|
|
41
|
+
build(params.with_indifferent_access)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def result(opts = {})
|
|
45
|
+
@context.evaluate(self, opts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def build(params)
|
|
49
|
+
collapse_multiparameter_attributes!(params).each do |key, value|
|
|
50
|
+
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
|
|
51
|
+
send("#{key}=", value)
|
|
52
|
+
elsif @context.ransackable_scope?(key, @context.object)
|
|
53
|
+
add_scope(key, value)
|
|
54
|
+
elsif base.attribute_method?(key)
|
|
55
|
+
base.send("#{key}=", value)
|
|
56
|
+
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
|
57
|
+
raise InvalidSearchError, "Invalid search term #{key}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def sorts=(args)
|
|
64
|
+
case args
|
|
65
|
+
when Array
|
|
66
|
+
args.each do |sort|
|
|
67
|
+
if sort.kind_of? Hash
|
|
68
|
+
sort = Nodes::Sort.new(@context).build(sort)
|
|
69
|
+
else
|
|
70
|
+
sort = Nodes::Sort.extract(@context, sort)
|
|
71
|
+
end
|
|
72
|
+
self.sorts << sort if sort
|
|
73
|
+
end
|
|
74
|
+
when Hash
|
|
75
|
+
args.each do |index, attrs|
|
|
76
|
+
sort = Nodes::Sort.new(@context).build(attrs)
|
|
77
|
+
self.sorts << sort
|
|
78
|
+
end
|
|
79
|
+
when String
|
|
80
|
+
self.sorts = [args]
|
|
81
|
+
else
|
|
82
|
+
raise InvalidSearchError,
|
|
83
|
+
"Invalid argument (#{args.class}) supplied to sorts="
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
alias :s= :sorts=
|
|
87
|
+
|
|
88
|
+
def sorts
|
|
89
|
+
@sorts
|
|
90
|
+
end
|
|
91
|
+
alias :s :sorts
|
|
92
|
+
|
|
93
|
+
def build_sort(opts = {})
|
|
94
|
+
new_sort(opts).tap do |sort|
|
|
95
|
+
self.sorts << sort
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def new_sort(opts = {})
|
|
100
|
+
Nodes::Sort.new(@context).build(opts)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def method_missing(method_id, *args)
|
|
104
|
+
method_name = method_id.to_s
|
|
105
|
+
getter_name = method_name.sub(/=$/, ''.freeze)
|
|
106
|
+
if base.attribute_method?(getter_name)
|
|
107
|
+
base.send(method_id, *args)
|
|
108
|
+
elsif @context.ransackable_scope?(getter_name, @context.object)
|
|
109
|
+
if method_name =~ /=$/
|
|
110
|
+
add_scope getter_name, args
|
|
111
|
+
else
|
|
112
|
+
@scope_args[method_name]
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
super
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def inspect
|
|
120
|
+
details = [
|
|
121
|
+
[:class, klass.name],
|
|
122
|
+
([:scope, @scope_args] if @scope_args.present?),
|
|
123
|
+
[:base, base.inspect]
|
|
124
|
+
]
|
|
125
|
+
.compact
|
|
126
|
+
.map { |d| d.join(': '.freeze) }
|
|
127
|
+
.join(', '.freeze)
|
|
128
|
+
|
|
129
|
+
"Ransack::Search<#{details}>"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
def add_scope(key, args)
|
|
135
|
+
sanitized_args = if Ransack.options[:sanitize_scope_args] && !@context.ransackable_scope_skip_sanitize_args?(key, @context.object)
|
|
136
|
+
sanitized_scope_args(args)
|
|
137
|
+
else
|
|
138
|
+
args
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
if @context.scope_arity(key) == 1
|
|
142
|
+
@scope_args[key] = args.is_a?(Array) ? args[0] : args
|
|
143
|
+
else
|
|
144
|
+
@scope_args[key] = args.is_a?(Array) ? sanitized_args : args
|
|
145
|
+
end
|
|
146
|
+
@context.chain_scope(key, sanitized_args)
|
|
147
|
+
end
|
|
148
|
+
|
|
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
|
+
def collapse_multiparameter_attributes!(attrs)
|
|
164
|
+
attrs.keys.each do |k|
|
|
165
|
+
if k.include?(Constants::LEFT_PARENTHESIS)
|
|
166
|
+
real_attribute, position = k.split(/\(|\)/)
|
|
167
|
+
cast =
|
|
168
|
+
if Constants::A_S_I.include?(position.last)
|
|
169
|
+
position.last
|
|
170
|
+
else
|
|
171
|
+
nil
|
|
172
|
+
end
|
|
173
|
+
position = position.to_i - 1
|
|
174
|
+
value = attrs.delete(k)
|
|
175
|
+
attrs[real_attribute] ||= []
|
|
176
|
+
attrs[real_attribute][position] =
|
|
177
|
+
if cast
|
|
178
|
+
if value.blank? && cast == Constants::I
|
|
179
|
+
nil
|
|
180
|
+
else
|
|
181
|
+
value.send("to_#{cast}")
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
value
|
|
185
|
+
end
|
|
186
|
+
elsif Hash === attrs[k]
|
|
187
|
+
collapse_multiparameter_attributes!(attrs[k])
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
attrs
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|