Fernando Luizão

Desenvolvimento de software e nerdices em geral

Archive for the ‘Databases’ Category

Insensitivity: O plugin insensível

leave a comment »

Consultas case insensitive e independentes de acentos que funcionem em qualquer SGBD são difíceis de conseguir, pois cada banco possui sua maneira específica de fazer isso. Se forem tomados alguns cuidados, é possível usar a sintaxe correta de acordo com o adaptador que estamos usando. No PostgreSQL por exemplo, para conseguir uma consulta case insensitive e independente de acentos, temos que fazer coisas assim ou assim.

O problema em usar conversões nas colunas é que, além delas não fazerem parte padrão SQL, perdemos os índices na coluna, o que vai fazer nossa consulta demorar um pouco mais (dependendo da quatidade de registros, usar ou não um índice pode fazer uma grande diferença). Para resolver esse problema, criei o plugin “Insensitivity“, que usa uma coluna extra para armazenar o valor sem acentos e em minúsculas. Assim, durante as consultas, o ActiveRecord irá utilizar essa coluna em vez da coluna com o valor real.

Vantagens dessa abordagem

Independente de banco
Se hover índices, serão usados

Desvantagens

Utiliza o dobro de espaço.

Instalando e usando o plugin

script/plugin install git://github.com/fernandoluizao/insensitivity.git

No seu model, você deve indicar quais campos usarão a pesquisa case insensitive:

class User < ActiveRecord:Base
  insensible :name, :email
end
&#91;/sourcecode&#93;

Depois, você <strong>DEVE</strong> adicionar à tabela, os campos com o mesmo nome dos que foram indicados e com o sufixo "_search". Se desejar, também coloque índices para melhorar a performance. Por exemplo:


script/generate migration add_search_fields

def self.up
  change_table :users do |t|
    t.string :name_search
    t.string :email_search
  end

  add_index :users, :name_search
  add_index :users, :email_search

  #Se sua tabela ja tiver dados, vc pode usar
  #User.make_insensible!
  #Isso vai inicializar os novos campos nos registros já existentes
end

def self.down
  change_table :users do |t|
    t.remove :name_search
    t.remove :email_search
  end
end

Para fazer as buscas, não muda nada. Veja as consultas geradas:

User.find_by_name('bla')
SELECT * FROM users WHERE name_search = 'bla'
User.find(:first, :conditions => ['name = ?', 'bla'], :order => 'name')
SELECT * FROM users WHERE name_search = 'bla' ORDER BY name LIMIT 1

Tudo funciona de forma transparente, sem vc precisar se preocupar =). Sua única preocupação deve ser passar o valor nas conditions sem acentos e em minusculas, para isso pode usar o método “insensible”, adicionado à classe String:

User.find(:first, :conditions => ['name LIKE ?', "%#{params[:name].insensible}%"])
SELECT * FROM users WHERE name_search LIKE '%bla%'

Bom, é isso, pesquisa sem sentimentos :). Quem quiser colaborar:

http://github.com/fernandoluizao/insensitivity/

PS: Testei apenas com rails 2.2.2. Pode não funcionar com versões mais antigas (< 2.0)

Written by fernandoluizao

February 10, 2009 at 11:25 pm