Olá pessoal. Tudo bem? Eu sou o Guilherme. Faço parte da equipe do laboratório de programação orientada ao objeto junto com o professor Fábio Kon e hoje eu vou falar pouquinho sobre o SQL Alchemy. O SQL Alchemy é 'framework' python feito para trabalhar com persistência de dados bancos de dados relacionais. A idéia dele é que ele forneça de maneira transparente, para quem utiliza o framework, funções e classes que façam essa comunicação com o banco de dados relacional. E deixem transparante para quem utiliza toda a implementação SQL por trás. Então, a idéia dele é que você não precise misturar código SQL e código Python quando você faz as suas aplicações com persistência. Ele abstrai a parte toda de comunicação com o banco deixando para o usuário do framework, no caso o programador, somente algumas funções e algumas classes para que sejam feitas diretamente python. Ele é framework bastante utilizado, inclusive, alguns dos exemplos de padrões de projeto de orientação ao objeto que foram feitos na parte são códigos extraídos do próprio SQL Alchemy. Então, o padrão adaptado ouro, o padrão estratégia, alguns exemplos códigos que estão lá na parte foram extraidos diretamente do código fonte do SQL Alchemy. Ele é utilizado algumas aplicações que já são bem estáveis, como o Reddit, o Dropbox e o SurveyMonkey. E eu vou, depois, disponibilizar esse notebook também para que vocês possam testar o código e fazer algumas alterações, se quiserem. Dando uma visão geral da arquitetura do SQL Alchemy, qualquer idéia, ele tem uma parte que é chamada de 'core' e uma que é chamada de ORM, que é onde está o exemplo que eu vou fazer nesse notebook. Então, a ideia é que a gente, de alguma maneira, comunica se com a API do banco de dados, seja ele Oracle, Postgres ou uma SQL. E essa conexão é feita através de motor que é divido duas partes. A parte do dialeto que vai se encarregar com as mudanças de sintaxe e de nome de comandos entre os diferentes dialetos SQL, Postgres, Oracle e por ai vai. E, também, gerenciador de conexões que é o 'pool' de conexões que gerencia as chamadas e o envio de mensagens pela rede para a API do banco de dados. Dentro do 'core' a gente ainda vai ter a chamada 'SQL Expression Language', que já é pacote de módulos e de funções feitas python para que você use somente a linguagem python para se comunicar com o banco abstraindo todo o comando SQL nativo. Então, você vai ter alguns métodos como o 'selection', o 'create table' e coisas do gênero, para você usar somente Python. E a parte de esquemas e tipos, também, que servem para fazer a conversão dos tipos de dados existente no python para os tipos de dados presentes na linguagem SQL nas diferentes implementações de SQL. O Python é uma linguagem dinamicamente tipada, então, a gente precisa ter algumas estratégias para conseguir garantir que nós vamos guardar os dados certos nas colunas certas do banco. E, no topo disso aqui, nós temos o ORM que é onde eu vou concentrar o exemplo que eu vou mostrar e que a idéia é fazer mesmo relacionamento entre objetos, sobre a parte que está aqui da linguagem de programação. E o banco de dados relacional onde a gente vai mapear algumas classes como sendo tabelas e alguns objetos que estão sendo instanciados e vão ser persistidos como linhas dessas tabelas que foram criadas. Então, o ORM é recurso bem avançado e que permite que a gente programe de maneira muito natural, na linguagem de programação, e a persistência fique muito transparente. Ela está implementada, mas a gente não precisa se preocupar tanto com a persistência. Então, indo para esse exemplo, como eu falei, esse notebook vai estar disponível para vocês poderem ver mais tarde, mas ele é adaptado de tutorial do próprio SQL, que está aqui linkado. E aqui eu vou usar o SQL Light como dialeto, SQL para fazer toda a implementação, mas tudo aqui poderia ser trocado por qualquer outro banco de dados, porque o SQL Alchemy faz esse gerenciamento de dialetos automático. A primeira coisa que a gente precisa fazer, então, é a gente instalar o framework, instala o pacote através do 'PIP'. E para começar a utilizar, a gente precisa criar o que a gente chama de motor que estava lá naquele esquema lá de cima. A gente se conecta com banco de dados através de uma ORL de conexão. Então, aqui eu estou usando a do próprio SQ Light, mas se eu fosse me conectar com uma SQL, eu iria por aqui uma SQL e iria colocar o endereço de onde está o servidor de uma SQL que eu quero me conectar ao banco, ou PostgreS, ou Oracle, ou qualquer outro flavor de SQL que eu quisesse usar. E através da função 'create engine', que vem no pacote do SQL Alchemy, eu crio esse motor. Então, essa função configura, monta, essa conexão através do dialeto e todas as configurações de rede necessárias, o número de conexões simultâneas, e devolve objeto do tipo motor para a gente poder se conectar então com a linguagem. Então, a gente pode executar aqui, ele vai criar esse motor e, a partir desse momento, a gente pode começar a fazer o mapeamento entre as nossas classes e o banco de dados. Então, como isso funciona? A estratégia principal que é utilizada aqui é a de herança, então, vai existir uma classe base, do SQL Alchemy, que ela já tem a implementação de como pegar atributo e persistir na coluna correta, como criar as tabelas, quais são os esquemas dessas tabelas no banco de dados, as funções para gerenciar, atualizar, o banco; ou atualizar o objeto de acordo com o que foi colocado no banco. E essa classe base é feita de uma maneira dinâmica, então, ela é montada através da chamada de uma função que lê exatamente quais são os detalhes do nosso motor. Então, a gente vai, mais para a frente, conectar essa base com o motor e ele vai ler exatamente qual é o dialeto a ser utilizado, qual o tipo de conexão que vai ser feito, qual é o endereço onde está o servidor de banco de dados que nós vamos nos conectar. Mas, por enquanto, eu vou instanciar então só a classe base. Então, notem aqui recurso bem legal da linguagem python que o resultado da chamada dessa função é uma classe, porque no python, classes também são objetos de primeira ordem. Então, elas são objetos, classes são objetos. Elas possuem meta classes. Então, eu posso ter objeto que é uma classe sendo retornado por uma função dentro do meu código. E aí, depois de criar essa classe base, eu posso importar todas as classes que fazem parte do pacote de relacionamentos, coisas para abstraírem colunas do banco de dados, os tipos de dados do banco de dados como o Integer, String e tabelas. E eu posso criar, então, a minha classe autor. Esse vai ser exemplo que vai trabalhar com livros e autores, então, a ideia é criar mini sistema que tem bibliotecas, mini sistema de bibliotecas. E aí eu crio a minha classe autor herdando da classe base e tudo que eu tenho que definir, eu não vou ter que definir nenhuma parte de como esses dados vão ser persistidos, ou salvos, mas eu preciso definir só a tabela, o nome da tabela onde eu gostaria de salvar lá no meu banco de dados, os dados dessa classe. E eu crio dois atributos de classe aqui que vão ser os atributos dos meus objetos e colunas do banco de dados. Então, são dois atributos do tipo 'column', onde eu dito o tipo de dado que vai ter nessa coluna, de acordo com a SQL, então, Integer, ou string de até 20 caracteres, que vai ser mapeada. E todas as outras restrições do SQL como o que é chave primária, seleção autoincrementais, seleção 'unique'. E, depois, o SQL Alchemy, de maneira automática, ele mapea isso para atributos de instância fazendo a checagem de tipo tempo real não permitindo que eu consigo gravar chat, uma coluna de init, ou boleano uma coluna init. Eu também vou definir aqui construtor para a minha classe onde, simplesmente, eu vou receber o nome do autor e vou gravar. Eu não vou precisar receber o ID, porque o ID vai ser auto gerado. Então, ele tem 'autoincrement' aqui. E também 'repr' que é para a gente ter uma representação básica do nosso objeto autor. Então, toda vez que eu pedir para olhar o que tem o objeto autor, ele vai me dar objeto da classe autor com determinado ID e nome. E eu faço o mesmo para a coluna livro, para a classe livro. Então, eu determino aqui uma tabela que vai ser a tabela livros no banco de dados. Também vai ter atributo que é ID, Integer, título, que é uma string de até 30 caracteres; e uma chave estrangeira para a nossa classe de autores, e para a nossa tabela de autores, para fazer o relacionamento. Já que livro possui autor e autor pode ter vários livros. E para esse relacionamento ficar ainda mais claro dentro da linguagem de programação, o SQL Alchemy provê essa função relationship que monta o relacionamento explícito entre os objetos e não só entre as tabelas com a chave estrangeira. Então, eu vou ter atributo chamado autor que me devolve objeto do tipo autor para cada livro. E ele também vai criar atributo 'livros' que vai ser uma lista de livros no meu autor. Então, isso fica muito mais transparente na linguagem de programação, muito mais fácil do que lidar com chaves estrangeiras e ter que fazer 'queries' para para achar alguns relacionamentos simples. Também vou criar aqui o construtor para a minha classe, onde eu vou ler o título do livro e vou receber o autor, já como objeto da classe autor não vai precisar ser o ID, então isso também fica muito mais fácil para manipular do lado da linguagem. E também fiz uma função de representação aqui onde eu coloco o ID do livro e o título. Uma vez criadas essas classes isso tudo vai ser armazenado dentro da nossa classe Base, num atributo metadata que cria o esquema do SQL que deve ser gerado e aí eu posso chamar essa função create_all, junto com o bind do motor, que vai literalmente criar isso no banco de dados. Então essa função create_all ela segura, caso as tabelas pretendidas já existam ele não sobrescreve, ele só faz o mapeamento com as tabelas já existentes ou ele cria as tabelas novas para refletir as classes que foram definidas dentro dessa metadata. Então, eu posso criá-la aqui. A partir desse momento as minhas tabelas já existem no banco de dados, o meu esquema já existe e aí tudo o que eu preciso fazer agora é popular essas tabelas criando objetos na linguagem Python e persistindo eles no SQL. Como é que eu vou fazer isso? Eu vou criar algumas instâncias de livros e autores da maneira que a gente faria normalmente qualquer linguagem de programação, eu vou criar objetos usando o construtor da classe autor e da classe livro. Então aqui eu estou criando alguns livros e alguns autores. Notem que eu já estou fazendo relacionamento aqui passando o autor de cada livro e quando eu executo eu vou ter todos esses objetos dentro do meu código Python, dentro do meu programa Python. E aí eu posso inclusive ver objeto que foi criado. Eu posso escolher o machado, por exemplo, e ver que ele realmente é autor, que ainda não possui ID e que o nome dele é Machado de Assis. Ele ainda não possui ID porque eu ainda não mandei ser persistido no banco e esse ID vai ser gerado somente quando ele for gravado no banco. Então por enquanto ele não tem ID, assim como os livros também ainda não possuem ID. Embora eles já estejam associados com o nosso autor, com o nosso objeto autor, eu posso puxar os livros, eles também ainda não possuem IDs porque eles só vão possuir esse ID quando eles forem persistidos no banco. E como é que essa persistência ocorre? O sqlalchemy vai ter conceito de sessão, então uma sessão é uma conexão com o banco onde a gente vai poder inserir objetos, remover objetos, alterar objetos e fazer busca de objetos e ela também é montada de uma maneira dinâmica através da função sessionmaker. Então ela faz bind com o motor, me devolve objeto da classe sessão e aí eu posso criar uma instância dessa sessão e adicionar objetos lá dentro e mandar ser gravado no banco, apagar objetos, buscar por objetos que estejam lá nessa sessão. Então eu posso executar aqui, crio a minha sessão e utilizando a minha sessão eu posso adicionar todos os objetos que eu já criei, dentro de uma lista e comitar. A partir do momento que eu faço commit essas informações são mesmo gravadas no banco que eu estou conetado, seja ele qualquer tipo de banco SQL. Então SQL é legal, a gente pode ter uma estratégia única código único que vai-se comunicar com diversos tipos de bancos de dados diferentes, conforme a necessidade. E a partir desse momento que eu gravo eles já vão ser gerados os IDs dos meus objetos. Então eu posso vir aqui, e se eu olhar o machado agora ele realmente tem o ID porque ele foi o primeiro autor que eu gravei e os livros também já vão ter os seus respectivos IDs gravados no banco. Então é assim que funciona. Se eu quiser adicionar mais livro, tudo o que eu tenho que fazer é instanciar mais objeto do tipo livro, adicionar à minha sessão e comitar. Se eu, por acaso, achar que teve algum erro e eu quiser voltar atrás, entre os commits eu sempre posso dar rollback e ele me volta ao estado do último commit realizado. Então, realmente como se fosse uma transação do banco de dados de maneira super bem implementada. E aí agora quando eu olho os livros do Machado de Assis eu vejo três livros. O e o dois foram gravados anteriormente e o livro de ID sete que foi gravado agora. Além de gravar e recuperar informações do banco de dados com os objetos eu posso querer fazer consultas também, que inclusive é dos maiores fatores de se usar bancos de dados. Essas consultas podem ser feitas através das sessões, então eu vou ter método query, com objeto do tipo sessão, onde eu posso passar qual é a tabela que eu estou fazendo essa busca, ou até os atributos que me interessam dessa busca, e o first é como se eu limitasse ao primeiro resultado, então pego somente o primeiro livro da tabela Livro, ele vai me devolver O Alienista, que era o nosso livro de ID mas é totalmente possível fazer queries tão complexas como necessário. Então a gente pode fazer uma query com join onde eu estou procurando todos os livros no join com autores e filtro que eu quero somente livros cujos autores sejam ou o Machado de Assis ou a Cecília Meireles e quero ordená-los por título do livro e aí eu quero recuperar todos. Quando eu faço essa query eu vou receber uma lista de livros, de objetos da classe livro, já ordenados pela ordem lexicográfica dos seus títulos e somente os que atendem ao critério do autor ser ou o Machado de Assis ou a Cecília Meireles. Então o sqlalchemy ele é esse framework que permite que a gente faça toda essa parte de consulta e inserção de dados no banco de dados e facilita o uso para você fazer aplicações que sejam cada vez mais complexas e que necessitem de estratégias de persistência cada vez mais alto nível, de maneira que fique simplificado dentro do seu código e o seu código fique limpo e objetivo. Então eu espero que vocês tenham gostado, o notebook vai estar disponível aqui caso vocês queiram brincar e até ao próximo vídeo. Até mais.