mini-fast-sys 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.
- checksums.yaml +7 -0
- data/mini-fast-sys.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 +70 -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,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
describe InvalidSearchError do
|
|
5
|
+
it 'inherits from ArgumentError' do
|
|
6
|
+
expect(InvalidSearchError.superclass).to eq(ArgumentError)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'can be instantiated with a message' do
|
|
10
|
+
error = InvalidSearchError.new('Test error message')
|
|
11
|
+
expect(error.message).to eq('Test error message')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'can be instantiated without a message' do
|
|
15
|
+
error = InvalidSearchError.new
|
|
16
|
+
expect(error.message).to eq('Ransack::InvalidSearchError')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'can be raised and caught' do
|
|
20
|
+
expect { raise InvalidSearchError.new('Test') }.to raise_error(InvalidSearchError, 'Test')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'can be raised and caught as ArgumentError' do
|
|
24
|
+
expect { raise InvalidSearchError.new('Test') }.to raise_error(ArgumentError, 'Test')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
module Nodes
|
|
5
|
+
describe Condition do
|
|
6
|
+
context 'bug report #1245' do
|
|
7
|
+
it 'preserves tuple behavior' do
|
|
8
|
+
ransack_hash = {
|
|
9
|
+
m: 'and',
|
|
10
|
+
g: [
|
|
11
|
+
{ title_type_in: ['["title 1", ""]'] }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
sql = Article.ransack(ransack_hash).result.to_sql
|
|
16
|
+
expect(sql).to include("IN (('title 1', ''))")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'with an alias' do
|
|
21
|
+
subject {
|
|
22
|
+
Condition.extract(
|
|
23
|
+
Context.for(Person), 'term_start', Person.first(2).map(&:name)
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
specify { expect(subject.combinator).to eq 'or' }
|
|
28
|
+
specify { expect(subject.predicate.name).to eq 'start' }
|
|
29
|
+
|
|
30
|
+
it 'converts the alias to the correct attributes' do
|
|
31
|
+
expect(subject.attributes.map(&:name)).to eq(['name', 'email'])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'with multiple values and an _any predicate' do
|
|
36
|
+
subject {
|
|
37
|
+
Condition.extract(
|
|
38
|
+
Context.for(Person), 'name_eq_any', Person.first(2).map(&:name)
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
specify { expect(subject.values.size).to eq(2) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#negative?' do
|
|
46
|
+
let(:context) { Context.for(Person) }
|
|
47
|
+
let(:eq) { Condition.extract(context, 'name_eq', 'A') }
|
|
48
|
+
let(:not_eq) { Condition.extract(context, 'name_not_eq', 'A') }
|
|
49
|
+
|
|
50
|
+
specify { expect(not_eq.negative?).to be true }
|
|
51
|
+
specify { expect(eq.negative?).to be false }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'with an invalid predicate' do
|
|
55
|
+
subject {
|
|
56
|
+
Condition.extract(
|
|
57
|
+
Context.for(Person), 'name_invalid', Person.first.name
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
context "when ignore_unknown_conditions is false" do
|
|
62
|
+
before do
|
|
63
|
+
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
specify { expect { subject }.to raise_error ArgumentError }
|
|
67
|
+
specify { expect { subject }.to raise_error InvalidSearchError }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context "when ignore_unknown_conditions is true" do
|
|
71
|
+
before do
|
|
72
|
+
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
specify { expect(subject).to be_nil }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context 'with an empty predicate' do
|
|
80
|
+
subject {
|
|
81
|
+
Condition.extract(
|
|
82
|
+
Context.for(Person), 'full_name', Person.first.name
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
context "when default_predicate = nil" do
|
|
87
|
+
before do
|
|
88
|
+
Ransack.configure { |c| c.default_predicate = nil }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
specify { expect(subject).to be_nil }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "when default_predicate = 'eq'" do
|
|
95
|
+
before do
|
|
96
|
+
Ransack.configure { |c| c.default_predicate = 'eq' }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
specify { expect(subject).to eq Condition.extract(Context.for(Person), 'full_name_eq', Person.first.name) }
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context 'with wildcard string values' do
|
|
104
|
+
it 'properly quotes values with wildcards for LIKE predicates' do
|
|
105
|
+
ransack_hash = { name_cont: 'test%' }
|
|
106
|
+
sql = Person.ransack(ransack_hash).result.to_sql
|
|
107
|
+
|
|
108
|
+
# The % should be properly quoted in the SQL
|
|
109
|
+
case ActiveRecord::Base.connection.adapter_name
|
|
110
|
+
when "Mysql2"
|
|
111
|
+
expect(sql).to include("LIKE '%test\\\\%%'")
|
|
112
|
+
expect(sql).not_to include("NOT LIKE '%test\\\\%%'")
|
|
113
|
+
when "PostGIS", "PostgreSQL"
|
|
114
|
+
expect(sql).to include("ILIKE '%test\\%%'")
|
|
115
|
+
expect(sql).not_to include("NOT ILIKE '%test\\%%'")
|
|
116
|
+
else
|
|
117
|
+
expect(sql).to include("LIKE '%test%%'")
|
|
118
|
+
expect(sql).not_to include("NOT LIKE '%test%%'")
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'properly quotes values with wildcards for NOT LIKE predicates' do
|
|
123
|
+
ransack_hash = { name_not_cont: 'test%' }
|
|
124
|
+
sql = Person.ransack(ransack_hash).result.to_sql
|
|
125
|
+
|
|
126
|
+
# The % should be properly quoted in the SQL
|
|
127
|
+
case ActiveRecord::Base.connection.adapter_name
|
|
128
|
+
when "Mysql2"
|
|
129
|
+
expect(sql).to include("NOT LIKE '%test\\\\%%'")
|
|
130
|
+
when "PostGIS", "PostgreSQL"
|
|
131
|
+
expect(sql).to include("NOT ILIKE '%test\\%%'")
|
|
132
|
+
else
|
|
133
|
+
expect(sql).to include("NOT LIKE '%test%%'")
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context 'with negative conditions on associations' do
|
|
139
|
+
it 'handles not_null predicate with true value correctly' do
|
|
140
|
+
ransack_hash = { comments_id_not_null: true }
|
|
141
|
+
sql = Person.ransack(ransack_hash).result.to_sql
|
|
142
|
+
|
|
143
|
+
# Should generate an IN query with IS NOT NULL condition
|
|
144
|
+
expect(sql).to include('IN (')
|
|
145
|
+
expect(sql).to include('IS NOT NULL')
|
|
146
|
+
expect(sql).not_to include('IS NULL')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'handles not_null predicate with false value correctly' do
|
|
150
|
+
ransack_hash = { comments_id_not_null: false }
|
|
151
|
+
sql = Person.ransack(ransack_hash).result.to_sql
|
|
152
|
+
|
|
153
|
+
# Should generate a NOT IN query with IS NULL condition
|
|
154
|
+
expect(sql).to include('NOT IN (')
|
|
155
|
+
expect(sql).to include('IS NULL')
|
|
156
|
+
expect(sql).not_to include('IS NOT NULL')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'handles not_cont predicate correctly' do
|
|
160
|
+
ransack_hash = { comments_body_not_cont: 'test' }
|
|
161
|
+
sql = Person.ransack(ransack_hash).result.to_sql
|
|
162
|
+
|
|
163
|
+
# Should generate a NOT IN query with LIKE condition (not NOT LIKE)
|
|
164
|
+
expect(sql).to include('NOT IN (')
|
|
165
|
+
expect(sql).to include("LIKE '%test%'")
|
|
166
|
+
expect(sql).not_to include("NOT LIKE '%test%'")
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context 'with nested conditions' do
|
|
171
|
+
it 'correctly identifies non-nested conditions' do
|
|
172
|
+
condition = Condition.extract(
|
|
173
|
+
Context.for(Person), 'name_eq', 'Test'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Create a mock parent table
|
|
177
|
+
parent_table = Person.arel_table
|
|
178
|
+
|
|
179
|
+
# Get the attribute name and make sure it starts with the table name
|
|
180
|
+
attribute = condition.attributes.first
|
|
181
|
+
expect(attribute.name).to eq('name')
|
|
182
|
+
expect(parent_table.name).to eq('people')
|
|
183
|
+
|
|
184
|
+
# The method should return false because 'name' doesn't start with 'people'
|
|
185
|
+
result = condition.send(:not_nested_condition, attribute, parent_table)
|
|
186
|
+
expect(result).to be false
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'correctly identifies truly non-nested conditions when attribute name starts with table name' do
|
|
190
|
+
# Create a condition with an attribute that starts with the table name
|
|
191
|
+
condition = Condition.extract(
|
|
192
|
+
Context.for(Person), 'name_eq', 'Test'
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Modify the attribute name to start with the table name for testing purposes
|
|
196
|
+
attribute = condition.attributes.first
|
|
197
|
+
allow(attribute).to receive(:name).and_return('people_name')
|
|
198
|
+
|
|
199
|
+
# Create a parent table
|
|
200
|
+
parent_table = Person.arel_table
|
|
201
|
+
|
|
202
|
+
# Now the method should return true because 'people_name' starts with 'people'
|
|
203
|
+
result = condition.send(:not_nested_condition, attribute, parent_table)
|
|
204
|
+
expect(result).to be true
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'correctly identifies nested conditions' do
|
|
208
|
+
condition = Condition.extract(
|
|
209
|
+
Context.for(Person), 'articles_title_eq', 'Test'
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Create a mock table alias
|
|
213
|
+
parent_table = Arel::Nodes::TableAlias.new(
|
|
214
|
+
Article.arel_table,
|
|
215
|
+
Article.arel_table
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Access the private method using send
|
|
219
|
+
result = condition.send(:not_nested_condition, condition.attributes.first, parent_table)
|
|
220
|
+
|
|
221
|
+
# Should return false for nested condition
|
|
222
|
+
expect(result).to be false
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
context 'with polymorphic associations and not_in predicate' do
|
|
227
|
+
before do
|
|
228
|
+
# Define test models for polymorphic associations
|
|
229
|
+
class ::TestTask < ActiveRecord::Base
|
|
230
|
+
self.table_name = 'tasks'
|
|
231
|
+
has_many :follows, primary_key: :uid, inverse_of: :followed, foreign_key: :followed_uid, class_name: 'TestFollow'
|
|
232
|
+
has_many :users, through: :follows, source: :follower, source_type: 'TestUser'
|
|
233
|
+
|
|
234
|
+
# Add ransackable_attributes method
|
|
235
|
+
def self.ransackable_attributes(auth_object = nil)
|
|
236
|
+
["created_at", "id", "name", "uid", "updated_at"]
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Add ransackable_associations method
|
|
240
|
+
def self.ransackable_associations(auth_object = nil)
|
|
241
|
+
["follows", "users"]
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
class ::TestFollow < ActiveRecord::Base
|
|
246
|
+
self.table_name = 'follows'
|
|
247
|
+
belongs_to :follower, polymorphic: true, foreign_key: :follower_uid, primary_key: :uid
|
|
248
|
+
belongs_to :followed, polymorphic: true, foreign_key: :followed_uid, primary_key: :uid
|
|
249
|
+
|
|
250
|
+
# Add ransackable_attributes method
|
|
251
|
+
def self.ransackable_attributes(auth_object = nil)
|
|
252
|
+
["created_at", "followed_type", "followed_uid", "follower_type", "follower_uid", "id", "updated_at"]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Add ransackable_associations method
|
|
256
|
+
def self.ransackable_associations(auth_object = nil)
|
|
257
|
+
["followed", "follower"]
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
class ::TestUser < ActiveRecord::Base
|
|
262
|
+
self.table_name = 'users'
|
|
263
|
+
has_many :follows, primary_key: :uid, inverse_of: :follower, foreign_key: :follower_uid, class_name: 'TestFollow'
|
|
264
|
+
has_many :tasks, through: :follows, source: :followed, source_type: 'TestTask'
|
|
265
|
+
|
|
266
|
+
# Add ransackable_attributes method
|
|
267
|
+
def self.ransackable_attributes(auth_object = nil)
|
|
268
|
+
["created_at", "id", "name", "uid", "updated_at"]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Add ransackable_associations method
|
|
272
|
+
def self.ransackable_associations(auth_object = nil)
|
|
273
|
+
["follows", "tasks"]
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Create tables if they don't exist
|
|
278
|
+
ActiveRecord::Base.connection.create_table(:tasks, force: true) do |t|
|
|
279
|
+
t.string :uid
|
|
280
|
+
t.string :name
|
|
281
|
+
t.timestamps null: false
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
ActiveRecord::Base.connection.create_table(:follows, force: true) do |t|
|
|
285
|
+
t.string :followed_uid, null: false
|
|
286
|
+
t.string :followed_type, null: false
|
|
287
|
+
t.string :follower_uid, null: false
|
|
288
|
+
t.string :follower_type, null: false
|
|
289
|
+
t.timestamps null: false
|
|
290
|
+
t.index [:followed_uid, :followed_type]
|
|
291
|
+
t.index [:follower_uid, :follower_type]
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
ActiveRecord::Base.connection.create_table(:users, force: true) do |t|
|
|
295
|
+
t.string :uid
|
|
296
|
+
t.string :name
|
|
297
|
+
t.timestamps null: false
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
after do
|
|
302
|
+
# Clean up test models and tables
|
|
303
|
+
Object.send(:remove_const, :TestTask)
|
|
304
|
+
Object.send(:remove_const, :TestFollow)
|
|
305
|
+
Object.send(:remove_const, :TestUser)
|
|
306
|
+
|
|
307
|
+
ActiveRecord::Base.connection.drop_table(:tasks, if_exists: true)
|
|
308
|
+
ActiveRecord::Base.connection.drop_table(:follows, if_exists: true)
|
|
309
|
+
ActiveRecord::Base.connection.drop_table(:users, if_exists: true)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it 'correctly handles not_in predicate with polymorphic associations' do
|
|
313
|
+
# Create the search
|
|
314
|
+
search = TestTask.ransack(users_uid_not_in: ['uid_example'])
|
|
315
|
+
sql = search.result.to_sql
|
|
316
|
+
|
|
317
|
+
# Verify the SQL contains the expected NOT IN clause
|
|
318
|
+
expect(sql).to include('NOT IN')
|
|
319
|
+
expect(sql).to include("follower_uid")
|
|
320
|
+
expect(sql).to include("followed_uid")
|
|
321
|
+
expect(sql).to include("'uid_example'")
|
|
322
|
+
|
|
323
|
+
# The SQL should include a reference to tasks.uid
|
|
324
|
+
expect(sql).to include("tasks")
|
|
325
|
+
expect(sql).to include("uid")
|
|
326
|
+
|
|
327
|
+
# The SQL should include a reference to follows table
|
|
328
|
+
expect(sql).to include("follows")
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
module Nodes
|
|
5
|
+
describe Grouping do
|
|
6
|
+
before do
|
|
7
|
+
@g = 1
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
let(:context) { Context.for(Person) }
|
|
11
|
+
|
|
12
|
+
subject { described_class.new(context) }
|
|
13
|
+
|
|
14
|
+
describe '#attribute_method?' do
|
|
15
|
+
context 'for attributes of the context' do
|
|
16
|
+
it 'is true' do
|
|
17
|
+
expect(subject.attribute_method?('name')).to be true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "when the attribute contains '_and_'" do
|
|
21
|
+
it 'is true' do
|
|
22
|
+
expect(subject.attribute_method?('terms_and_conditions')).to be true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "when the attribute contains '_or_'" do
|
|
27
|
+
it 'is true' do
|
|
28
|
+
expect(subject.attribute_method?('true_or_false')).to be true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "when the attribute ends with '_start'" do
|
|
33
|
+
it 'is true' do
|
|
34
|
+
expect(subject.attribute_method?('life_start')).to be true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when the attribute ends with '_end'" do
|
|
39
|
+
it 'is true' do
|
|
40
|
+
expect(subject.attribute_method?('stop_end')).to be true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'for unknown attributes' do
|
|
46
|
+
it 'is false' do
|
|
47
|
+
expect(subject.attribute_method?('not_an_attribute')).to be false
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#conditions=' do
|
|
53
|
+
context 'when conditions are identical' do
|
|
54
|
+
let(:conditions) do
|
|
55
|
+
{
|
|
56
|
+
'0' => {
|
|
57
|
+
'a' => { '0'=> { 'name' => 'name', 'ransacker_args' => '' } },
|
|
58
|
+
'p' => 'cont',
|
|
59
|
+
'v' => { '0' => { 'value' => 'John' } }
|
|
60
|
+
},
|
|
61
|
+
'1' => {
|
|
62
|
+
'a' => { '0' => { 'name' => 'name', 'ransacker_args' => '' } },
|
|
63
|
+
'p' => 'cont',
|
|
64
|
+
'v' => { '0' => { 'value' => 'John' } }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
before { subject.conditions = conditions }
|
|
70
|
+
|
|
71
|
+
it 'expect duplicates to be removed' do
|
|
72
|
+
expect(subject.conditions.count).to eq 1
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'when conditions differ only by ransacker_args' do
|
|
77
|
+
let(:conditions) do
|
|
78
|
+
{
|
|
79
|
+
'0' => {
|
|
80
|
+
'a' => {
|
|
81
|
+
'0' => {
|
|
82
|
+
'name' => 'with_arguments',
|
|
83
|
+
'ransacker_args' => [1, 2]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
'p' => 'eq',
|
|
87
|
+
'v' => { '0' => { 'value' => '10' } }
|
|
88
|
+
},
|
|
89
|
+
'1' => {
|
|
90
|
+
'a' => {
|
|
91
|
+
'0' => {
|
|
92
|
+
'name' => 'with_arguments',
|
|
93
|
+
'ransacker_args' => [3, 4]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
'p' => 'eq',
|
|
97
|
+
'v' => { '0' => { 'value' => '10' } }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
before { subject.conditions = conditions }
|
|
103
|
+
|
|
104
|
+
it 'expect them to be parsed as different and not as duplicates' do
|
|
105
|
+
expect(subject.conditions.count).to eq 2
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
module Nodes
|
|
5
|
+
describe Value do
|
|
6
|
+
let(:context) { Context.for(Person) }
|
|
7
|
+
|
|
8
|
+
subject do
|
|
9
|
+
Value.new(context, raw_value)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context "with a date value" do
|
|
13
|
+
let(:raw_value) { "2022-05-23" }
|
|
14
|
+
|
|
15
|
+
[:date].each do |type|
|
|
16
|
+
it "should cast #{type} correctly" do
|
|
17
|
+
result = subject.cast(type)
|
|
18
|
+
|
|
19
|
+
expect(result).to be_a_kind_of(Date)
|
|
20
|
+
expect(result).to eq(Date.parse(raw_value))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "with a timestamp value" do
|
|
26
|
+
let(:raw_value) { "2022-05-23 10:40:02 -0400" }
|
|
27
|
+
|
|
28
|
+
[:datetime, :timestamp, :time, :timestamptz].each do |type|
|
|
29
|
+
it "should cast #{type} correctly" do
|
|
30
|
+
result = subject.cast(type)
|
|
31
|
+
|
|
32
|
+
expect(result).to be_a_kind_of(Time)
|
|
33
|
+
expect(result).to eq(Time.zone.parse(raw_value))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Constants::TRUE_VALUES.each do |value|
|
|
39
|
+
context "with a true boolean value (#{value})" do
|
|
40
|
+
let(:raw_value) { value.to_s }
|
|
41
|
+
|
|
42
|
+
it "should cast boolean correctly" do
|
|
43
|
+
result = subject.cast(:boolean)
|
|
44
|
+
expect(result).to eq(true)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Constants::FALSE_VALUES.each do |value|
|
|
50
|
+
context "with a false boolean value (#{value})" do
|
|
51
|
+
let(:raw_value) { value.to_s }
|
|
52
|
+
|
|
53
|
+
it "should cast boolean correctly" do
|
|
54
|
+
result = subject.cast(:boolean)
|
|
55
|
+
|
|
56
|
+
expect(result).to eq(false)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
["12", "101.5"].each do |value|
|
|
62
|
+
context "with an integer value (#{value})" do
|
|
63
|
+
let(:raw_value) { value }
|
|
64
|
+
|
|
65
|
+
it "should cast #{value} to integer correctly" do
|
|
66
|
+
result = subject.cast(:integer)
|
|
67
|
+
|
|
68
|
+
expect(result).to be_an(Integer)
|
|
69
|
+
expect(result).to eq(value.to_i)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
[[], ["12"], ["101.5"]].each do |value|
|
|
75
|
+
context "with an array value (#{value.inspect})" do
|
|
76
|
+
let(:raw_value) { value }
|
|
77
|
+
|
|
78
|
+
it "should cast to integer as nil" do
|
|
79
|
+
result = subject.cast(:integer)
|
|
80
|
+
|
|
81
|
+
expect(result).to be nil
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
["12", "101.5"].each do |value|
|
|
87
|
+
context "with a float value (#{value})" do
|
|
88
|
+
let(:raw_value) { value }
|
|
89
|
+
|
|
90
|
+
it "should cast #{value} to float correctly" do
|
|
91
|
+
result = subject.cast(:float)
|
|
92
|
+
|
|
93
|
+
expect(result).to be_an(Float)
|
|
94
|
+
expect(result).to eq(value.to_f)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
["12", "101.5"].each do |value|
|
|
100
|
+
context "with a decimal value (#{value})" do
|
|
101
|
+
let(:raw_value) { value }
|
|
102
|
+
|
|
103
|
+
it "should cast #{value} to decimal correctly" do
|
|
104
|
+
result = subject.cast(:decimal)
|
|
105
|
+
|
|
106
|
+
expect(result).to be_a(BigDecimal)
|
|
107
|
+
expect(result).to eq(value.to_d)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
["12", "101.513"].each do |value|
|
|
113
|
+
context "with a money value (#{value})" do
|
|
114
|
+
let(:raw_value) { value }
|
|
115
|
+
|
|
116
|
+
it "should cast #{value} to money correctly" do
|
|
117
|
+
result = subject.cast(:money)
|
|
118
|
+
|
|
119
|
+
expect(result).to be_a(String)
|
|
120
|
+
expect(result).to eq(value.to_f.to_s)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|