Skip to content

Commit f521633

Browse files
authored
Merge pull request #2766 from tinbka/master
Search query: Added ILIKE support for PostGIS adapter, multibyte downcase for other adapters; support for UUID
2 parents 6642acd + 1256182 commit f521633

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

lib/rails_admin/adapters/active_record.rb

+17-5
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def build_statement_for_type
204204
when :string, :text then build_statement_for_string_or_text
205205
when :enum then build_statement_for_enum
206206
when :belongs_to_association then build_statement_for_belongs_to_association
207+
when :uuid then build_statement_for_uuid
207208
end
208209
end
209210

@@ -223,22 +224,27 @@ def build_statement_for_belongs_to_association
223224

224225
def build_statement_for_string_or_text
225226
return if @value.blank?
227+
228+
unless ['postgresql', 'postgis'].include? ar_adapter
229+
@value = @value.mb_chars.downcase
230+
end
231+
226232
@value = begin
227233
case @operator
228234
when 'default', 'like'
229-
"%#{@value.downcase}%"
235+
"%#{@value}%"
230236
when 'starts_with'
231-
"#{@value.downcase}%"
237+
"#{@value}%"
232238
when 'ends_with'
233-
"%#{@value.downcase}"
239+
"%#{@value}"
234240
when 'is', '='
235-
@value.downcase
241+
@value
236242
else
237243
return
238244
end
239245
end
240246

241-
if ar_adapter == 'postgresql'
247+
if ['postgresql', 'postgis'].include? ar_adapter
242248
["(#{@column} ILIKE ?)", @value]
243249
else
244250
["(LOWER(#{@column}) LIKE ?)", @value]
@@ -250,6 +256,12 @@ def build_statement_for_enum
250256
["(#{@column} IN (?))", Array.wrap(@value)]
251257
end
252258

259+
def build_statement_for_uuid
260+
if @value.to_s =~ /\A[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}\z/
261+
column_for_value(@value)
262+
end
263+
end
264+
253265
def ar_adapter
254266
::ActiveRecord::Base.connection.adapter_name.downcase
255267
end

spec/rails_admin/adapters/active_record_spec.rb

+25-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
describe 'RailsAdmin::Adapters::ActiveRecord', active_record: true do
55
before do
6-
@like = if ::ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'postgresql'
6+
@like = if ['postgresql', 'postgis'].include? ::ActiveRecord::Base.configurations[Rails.env]['adapter']
77
'(field ILIKE ?)'
88
else
99
'(LOWER(field) LIKE ?)'
@@ -36,7 +36,11 @@ def predicates_for(scope)
3636
let(:abstract_model) { RailsAdmin::AbstractModel.new('Player') }
3737

3838
before do
39-
@players = FactoryGirl.create_list(:player, 3)
39+
@players = FactoryGirl.create_list(:player, 3) + [
40+
# Multibyte players
41+
FactoryGirl.create(:player, name: 'Антоха'),
42+
FactoryGirl.create(:player, name: 'Петруха'),
43+
]
4044
end
4145

4246
it '#new returns instance of AbstractObject' do
@@ -77,7 +81,7 @@ class PlayerWithDefaultScope < Player
7781

7882
it '#destroy destroys multiple items' do
7983
abstract_model.destroy(@players[0..1])
80-
expect(Player.all).to eq(@players[2..2])
84+
expect(Player.all).to eq(@players[2..-1])
8185
end
8286

8387
it '#where returns filtered results' do
@@ -102,8 +106,8 @@ class PlayerWithDefaultScope < Player
102106
end
103107

104108
it 'supports pagination' do
105-
expect(abstract_model.all(sort: 'id', page: 2, per: 1)).to eq(@players[1..1])
106-
expect(abstract_model.all(sort: 'id', page: 1, per: 2)).to eq(@players[1..2].reverse)
109+
expect(abstract_model.all(sort: 'id', page: 2, per: 1)).to eq(@players[-2, 1])
110+
expect(abstract_model.all(sort: 'id', page: 1, per: 2)).to eq(@players[-2, 2].reverse)
107111
end
108112

109113
it 'supports ordering' do
@@ -115,6 +119,13 @@ class PlayerWithDefaultScope < Player
115119
expect(results).to eq(@players[1..1])
116120
end
117121

122+
it 'supports multibyte querying' do
123+
unless ::ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'sqlite3'
124+
results = abstract_model.all(query: @players[4].name)
125+
expect(results).to eq(@players[4, 1])
126+
end
127+
end
128+
118129
it 'supports filtering' do
119130
expect(abstract_model.all(filters: {'name' => {'0000' => {o: 'is', v: @players[1].name}}})).to eq(@players[1..1])
120131
end
@@ -201,8 +212,10 @@ def build_statement(type, value, operator)
201212
end
202213

203214
it 'performs case-insensitive searches' do
204-
expect(build_statement(:string, 'foo', 'default')).to eq([@like, '%foo%'])
205-
expect(build_statement(:string, 'FOO', 'default')).to eq([@like, '%foo%'])
215+
unless ['postgresql', 'postgis'].include?(::ActiveRecord::Base.configurations[Rails.env]['adapter'])
216+
expect(build_statement(:string, 'foo', 'default')).to eq([@like, '%foo%'])
217+
expect(build_statement(:string, 'FOO', 'default')).to eq([@like, '%foo%'])
218+
end
206219
end
207220

208221
it "supports '_blank' operator" do
@@ -380,6 +393,11 @@ def build_statement(type, value, operator)
380393
it 'supports enum type query' do
381394
expect(build_statement(:enum, '1', nil)).to eq(['(field IN (?))', ['1']])
382395
end
396+
397+
it 'supports uuid type query' do
398+
uuid = SecureRandom.uuid
399+
expect(build_statement(:uuid, uuid, nil)).to eq(['(field = ?)', uuid])
400+
end
383401
end
384402

385403
describe 'model attribute method' do

0 commit comments

Comments
 (0)