[Rio-pm] Fey::ORM alguém já usou ou viu, tem futuro?
breno
breno em rio.pm.org
Segunda Dezembro 13 16:03:27 PST 2010
2010/12/12 German Valenzuela <german.valenzuela em gmail.com>:
> Prezados
>
> hoje ouvi falar do Fey::ORM alguém já usou ou viu, tem futuro?
>
Resposta curta
ou "preguiça de ler os emails enormes do garu"
=======================================
* Considerando as datas/quantidade de releases, a qualidade do
código, a documentação e o histórico/comprometimento do autor, eu
diria que tem futuro sim =)
* O projeto Fey é relativamente antigo (2006~2010) e bastante
estável, mas o Fey::ORM ainda é muito novo e a API pode mudar de uma
versão pra outra, então use com cuidado (ou "olhe o Changelog antes de
atualizar").
* Uma solução ORM estável e alternativa ao Fey::ORM (porém mais
inchada e que não usa Fey por baixo) é o famoso DBIx::Class (DBIC para
os íntimos).
Resposta longa
ou "o Fey mais Bunitin do pedaço :P"
ou "prévia do meu artigo para o equinócio de março/2011"
================================================
"Fey" é uma distribuição contendo uma série de módulos para
representar de forma simples e flexível os componentes de um schema
DBMS, bem como gerar queries SQL dinamicamente conforme esse schema.
Digamos que vc tenha um banco SQLite em "banco.db". Vc pode obter o
schema assim (strict e warnings omitidos apenas por brevidade):
--------------8<--------------
use DBI;
use Fey::Loader;
my $dbh = DBI->connect( 'dbi:SQLite:dbname=banco.db' )
or die "erro conectando-se ao banco";
my $schema = Fey::Loader->new( dbh => $dbh )->make_schema;
-------------->8--------------
A partir daí vc pode manipular seu $schema como quiser, através dos
métodos oferecidos pelo Fey::Schema - tables(), add_table(),
remove_table(), add_foreign_key(), etc. Fey também oferece o
Fey::DBIManager, uma interface única para um ou mais fontes de dados,
permitindo o gerenciamento deles em um só lugar, além de garantir, por
exemplo, que os handles DBI sejam recriados corretamente após uma
operação de fork.
Para obter/manipular as tabelas 'user' e 'group' do seu banco (supondo
que elas existem, claro), bastaria fazer:
--------------8<--------------
my $user = $schema->table('user');
my $group = $schema->table('group');
-------------->8--------------
São retornados objetos Fey::Table, com uma série de métodos
auxiliares. As operações em SQL (select, insert, update, delete ) são
manipuladas através de objetos também. Por exemplo:
--------------8<--------------
use Fey::SQL;
my $query = Fey::SQL->new_select;
$query->select( $user->columns( 'user_id', 'username' ) )
->from( $user, $group )
->where( $group->column('group_id'), 'IN', 1, 2, 3 )
->order_by( $user->column('username'), 'DESC' )
->limit( 10 );
-------------->8--------------
O código acima é equivalente (e argumentativamente mais fácil de
entender/manter) do que escrever uma string com o código SQL nativo
para o DBI:
--------------8<--------------
my $statement = <<'EOSQL';
SELECT user.user_id, User.username
FROM user JOIN Group
ON user.user_id = Group.user_id
WHERE group.group_id IN (?, ?, ?)
ORDER BY user.username DESC
LIMIT 10
EOSQL
-------------->8--------------
Como mostrado no exemplo mais acima, seu select é construído através
de métodos do Fey::SQL (no caso, Fey::SQL::Select). Você pode até
manipular funções com ele:
--------------8<--------------
my $func = Fey::Literal::Function->new( 'LCASE', $user->column('username') );
-------------->8--------------
e depois fazer algo como:
--------------8<--------------
$query->select( ...
...
->and( $func, 'LIKE', 'breno%' )
...
-------------->8--------------
Fey lida apenas com a geração de SQL. Ao terminar de escrever sua
query, vc pode executá-la como uma invocação DBI tradicional:
--------------8<--------------
my $rv = $dbh->prepare( $query->sql($dbh) )
->execute( $query->bind_params )
-------------->8--------------
A extensão FeyX::Active permite a integração do Fey com o seu DBI
handler. Assim, se $query fosse um "FeyX::Active::SQL" em vez de um
"Fey::SQL", poderiamos fazer a execução diretamente:
--------------8<--------------
my @linha = $query->execute->fetchrow
-------------->8--------------
Finalmente, para aqueles que procuram usar o Fey em um mapeamento
objeto-relacional, foi criado o Fey::ORM. Vejamos um exemplo
extremamente simples, a partir de um banco SQLite3 armazenado em
/var/myapp.db e com o seguinte schema:
CREATE TABLE User (
user_id integer not null primary key autoincrement,
username text not null,
email text null,
UNIQUE(username)
);
O primeiro passo é criar uma classe pra representar o schema do nosso
modelo, Digamos, MyApp::Model::Schema:
--------------8<--------------
package MyApp::Model::Schema;
use strict;
use warnings;
use Fey::ORM::Schema;
use Fey::Loader;
use Fey::DBIManager::Source;
my $source = Fey::DBIManager::Source->new(
dsn => 'dbi:SQLite:dbname=/var/myapp.db'
);
has_schema( Fey::Loader->new( dbh => $source->dbh )->make_schema );
__PACKAGE__->DBIManager->add_source( $source );
-------------->8--------------
No código acima definimos um $source - um wrapper para handles DBI
como já explicado - e dizemos que nossa classe possui o schema
carregado pelo Fey::Loader. Basta isso. Como vimos, o Fey se vira pra
criar uma representação do schema pra vc.
Agora vamos criar as classes das nossas tabelas, nesse exemplo apenas 'User':
--------------8<--------------
package MyApp::Model::User;
use strict;
use warnings;
use MyApp::Model::Schema;
use Fey::ORM::Table;
has_table( MyApp::Model::Schema->Schema->table('User') );
1;
-------------->8--------------
Quando definimos que essa classe deve usar a tabela "User" extraida do
nosso schema MyApp::Model::Schema->Schema(), o Fey::ORM cria pra vc
todos os accessors para as colunas da tabela em questão, além de
oferecer outros métodos bastante convenientes.
A partir daí, podemos usar nosso modelo como quisermos! Por exemplo,
veja o programa myapp.pl:
--------------8<--------------
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.0;
use MyApp::Model::User;
# adicionando um usuário
my $user = MyApp::Model::User->insert(
username => 'german',
email => 'german.valenzuela em gmail.com',
);
# exibindo informações do usuário
say $user->username; # 'german'
# buscando usuários
my $result = MyApp::Model::User->new( username => 'german' );
# atualizando entradas
$result->update( username => 'valenzuela' );
# removendo entradas
$user->delete;
-------------->8--------------
Os atributos (username, email, etc) são carregados apenas uma vez (e
todos de uma vez, por questões de eficiência), e depois servidos via
cache.
Você pode definir relacionamentos entre tabelas através de chamadas a
has_one() e has_many(). Por exemplo, se tivéssemos uma tabela
"Messages" com posts de cada usuário, poderiamos escrever em nosso
User.pm algo como:
--------------8<--------------
has_many 'messages', table => Forum::Model::Schema->Schema->table('Message');
-------------->8--------------
e a partir daí poderíamos acessar diretamente todas as mensagens de
nosso usuário:
--------------8<--------------
my $messages = $user->messages;
while ( my $message = $messages->next ) {
say $message->message_id;
}
-------------->8--------------
Outra coisa bacana é a criação de inflators/deflators para suas
colunas. Isso é muito usado quando vc quer transformar os dados de uma
coluna em um objeto para manipulação (inflar) e reverter o processo
para armazenar novamente no banco (desinflar). Por exemplo, vamos
voltar a nossa classe User.pm e transformar o campo "email" em um
objeto Email::Address:
--------------8<--------------
transform 'email'
=> inflate { defined $_[1] ? Email::Address->new( $_[1] ) : undef }
=> deflate { defined $_[1] && blessed $_[1] ? $_[1]->address() : $_[1] }
;
-------------->8--------------
É isso. Tanto Fey quanto suas extensões (entre elas o Fey::ORM)
possuem uma série de opções pra facilitar a vida de quem manipula
queries, muito mais do que cabem neste (já bem longo) email. A
documentação está cheia de exemplos e o suporte ao módulo oferecido
por autarch e companhia em #fey no irc.perl.org e no RT é digno de
respeito. Fey está na minha lista pessoal de módulos modernos para
Perl, e outras pessoas parecem concordar comigo. Dito isso, manipular
bancos de dados é algo muito particular às suas preferências e
necessidades. Escolha seu veneno e seja feliz =)
[]s
garu
Mais detalhes sobre a lista de discussão Rio-pm