Here's what I'd do:
First, data like email addresses and username fields for lookups should be
normalized to lowercase in the database. This simplifies your coding greatly.
If you need to maintain the original case, such as for a user's first and last
name for display, keep them as separate first and last name fields, and create
a separate field where they're already joined and hashed for searching, and use the same hash in your code when you look in that field. If that's indexed it'd be a very fast lookup compared to using a like
search.
Here's code to programmatically generate a where
using pure Sequel, rather than generate a SQL partial and inject it into your query. Notice that Sequel is aware of SQLite's syntax, and automatically creates a where clause that works. The same would apply if you're connecting to a PostgreSQL, MySQL, Oracle, MSSQL, Sybase or other DBM that Sequel supports; You won't have to tweak your code just to make it work, you'd only adjust your DSN telling Sequel which driver to use and what the DB credentials are.
Building a test DB:
require 'sequel'
DB = Sequel.sqlite
DB.create_table :items do
primary_key :id
String :first_name
String :last_name
String :email
String :attr1, :default => 'attr'
String :attr2, :default => 'attr'
end
items = DB[:items]
%w[Jane Jim John Junior].each do |fn|
items.insert(:first_name => fn, :last_name => 'Doe', :email => fn.downcase + 'doe@email.com')
end
puts items.all
And here we go...:
user_name = '%' + 'John Doe'.downcase + '%'
query = DB[:items].where(
Sequel.ilike(
Sequel.join([:first_name, :last_name], ' '),
user_name
)
)
columns = [:email, :attr1, :attr2]
columns.each do |col|
query = query.or(
Sequel.ilike(
col,
user_name.delete(' ')
)
)
end
puts query.sql
puts query.first
Running the code outputs the table's contents:
{:id=>1, :first_name=>"Jane", :last_name=>"Doe", :email=>"janedoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>2, :first_name=>"Jim", :last_name=>"Doe", :email=>"jimdoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>3, :first_name=>"John", :last_name=>"Doe", :email=>"johndoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>4, :first_name=>"Junior", :last_name=>"Doe", :email=>"juniordoe@email.com", :attr1=>"attr", :attr2=>"attr"}
The SQL generated to query the DB:
SELECT * FROM `items` WHERE ((UPPER((`first_name` || ' ' || `last_name`)) LIKE UPPER('%john doe%') ESCAPE '\') OR (UPPER(`email`) LIKE UPPER('%johndoe%') ESCAPE '\') OR (UPPER(`attr1`) LIKE UPPER('%johndoe%') ESCAPE '\') OR (UPPER(`attr2`) LIKE UPPER('%johndoe%') ESCAPE '\'))
Formatting that for readability:
SELECT * FROM `items`
WHERE (
(UPPER((`first_name` || ' ' || `last_name`)) LIKE UPPER('%john doe%') ESCAPE '\') OR
(UPPER(`email`) LIKE UPPER('%johndoe%') ESCAPE '\') OR
(UPPER(`attr1`) LIKE UPPER('%johndoe%') ESCAPE '\') OR
(UPPER(`attr2`) LIKE UPPER('%johndoe%') ESCAPE '\')
)
And the resulting row after the query:
{:id=>3, :first_name=>"John", :last_name=>"Doe", :email=>"johndoe@email.com", :attr1=>"attr", :attr2=>"attr"}
It's not the most DRY code, but for an example it gets the point across.