Usando SQL com Lua
Já há bastante tempo existe em programação a ideia de separar os dados da lógica do programa e, quando queremos poder fazer consultas estruturadas, bancos de dados relacionais são ótimos.
Primeiro as consultas eram feitas usando um pré-processamento que lia códigos estranhos à linguagem inseridos entre marcações de início e fim, mais ou menos assim:
EXEC SQL
DECLARE CUR CURSOR FOR
SELECT * FROM cadastro
WHERE grupo = 1
END-EXEC.
Mas era necessário rodar o pré-compilador, que substituía esses trechos por códigos mais complexos, o que era no mínimo desconfortável.
Mais tarde pensaram em fazer diferente: módulos com funções que recebem strings representando os comandos SQL (Structured Query Language) e os executam, «escondendo» assim toda complexidade do acesso sem necessidade de uma pré-compilação.
Outras sintaxes para acesso, também abstraindo a complexidade, foram desenvolvidas, como SQLObject e SQLAlchemy, mas nenhuma tão simples e popular quanto a simples passagem de uma string como parâmetro de uma função.
Por exemplo, em Python, temos o módulo MySQLdb:
import MySQLdb as mysql
conn = mysql.connect(
host="localhost",
user="batalema",
password="sEnH4",
db="empresa"
)
conn.query("""
SELECT * FROM cadastro WHERE grupo = 1
""")
cur = conn.use_result()
A conexão deve ser fechada com
conn.close()
. Os resultados de uma consulta são lidos com um tipo especial de reiterador chamado cursor. Isso permite que tabelas de centenas (ou milhares) de linhas (tuplas) sejam tratadas com muito pouco uso de memória. Já escrevi alguns artigos sobre o assunto.LuaSQL
Seguindo o exemplo de Python, PHP e outras linguagens, Lua também envia os comandos SQL por meio de strings como parâmetros de funções para uma conexão e percorre os resultados com um cursor.
O módulo de Lua para acesso a SQL é LuaSQL, que é parte do projeto Kepler, uma plataforma para desenvolvimento web usando Lua. Por isso é recomendável instalar tanto Lua quanto LuaSQL através da instalação completa de Kepler 1.1 – no momento em que este artigo foi escrito, só havia disponíveis snapshots (release-cadidates). Também é recomendável a instalação de todos os pacotes opcionais (
--with-optional=lualogging,luasql,luaexpat,luazip,md5
).Podemos ver agora como fazer os acessos usando LuaSQL.
O módulo traz submódulos de acesso a diversos SGBDs diferentes: MySQL (
luasql.mysql
), Oracle (luasql.oci8
), PostgreSQL (luasql.postgres
), SQLite (luasql.sqlite
) e MS SQL Server (via ODBC: luasql.odbc
). Vamos usar o padrão, luasql.mysql
.Em LuaSQL, antes de conectar ao SGBD, é preciso criar um ambiente de conexão:
require "luasql.mysql"
local env = assert(luasql.mysql())
A partir do ambiente podemos iniciar a conexão:
local conn = assert(
env:connect(
"empresa",
"batalema",
"sEnH4",
"localhost"
)
)
A ordem dos parâmetros (para
luasql.mysql
e luasql.postgresql
, para outros ambientes veja o manual) é:- Fonte (nome da base de dados)
- Usuário
- Senha
- Servidor
Efetuada a conexão, podemos criar nosso cursor. Precisaremos ainda de uma tabela Lua para receber cada uma das linhas da tabela SQL, chamadas tuplas:
local cur = conn:execute [[
SELECT * FROM cadastro WHERE grupo = 1
]]
local t = {}
O cursor possui dois métodos interessantes, um é
numrows()
, que retorna o número de tuplas da seleção, outro é fetch()
, que retorna a próxima tupla ou nil
se estiver chegado ao final.O método
fetch()
recebe dois parâmetros: ¹a tabela que receberá a tupla e ²uma string que indica como a tupla será interpretada pela tabela Lua.Há duas opções para o 2º parâmetro:
"n"
: os registros serão recebidos como pares índice-valor e a tabela será uma tabela indexada;"a"
: os registros serão recebidos como pares chave-valor e a tabela será uma tabela associativa.
Então, para listar os resultados podemos fazer algo bem simples:
while cur:fetch(t, "a") do
table.foreach(t, print)
end
Para finalizar precisamos fechar o cursor, a conexão e o ambiente:
cur:close()
conn:close()
env:close()
Outros comandos SQL
O comando
SELECT
retorna um cursor para a tabela retornada, mas outros comandos não retornam cursores ou tabelas.Em vez disso os demais comandos retornam o número de tuplas afetadas.
Conclusão
Se alguém ficou decepcionado, desculpe-me a falta de complexidade… mas o módulo é simples mesmo. =P
Aliás, todos os módulos do projeto Kepler são simples.
Para um pouco mais de «complexidade» (hehehe), veja o manual.
[]'s
PS: Publicado também no Kodumaro.