Primeiras aulas do curso Datomic: Schemas e Regras

Datomic: Schemas e Regras

Schemas e schemas - Introdução

Bem-vindo a mais um curso de Datomic. Nesse curso a gente vai falar de diversas questões importantes no dia a dia da utilização do Datomic, principalmente algumas questões que vão aparecer em função de a gente estar trabalhando com o esquema do nosso banco e o esquema dos nossos dados, nossos modelos, entidades. Então a gente vai ver que o nosso modelo, a nossa entidade vai começar a ficar mais complexa, começa a ficar cada vez mais complexa e vai ter seus dilemas.

Meu esquema que eu estou utilizando do Plumetic nos meus modelos é diferente, as regras são diferentes das regras que eu utilizo no meu banco. Devo mantê-las 100% compatíveis ou não? Devo ser mais aberto numa situação, mais fechado em outra? O que eu devo fazer?

E aí vão surgir diversas questões. Quando eu vou aceitar o nulo? Quando eu vou aceitar a não presença de um valor? No banco, no Datomic, ou no meu modelo? São questões comuns para qualquer banco de dados em qualquer linguagem. E aqui a gente vai ver, como o Clojure permite várias abordagens, a gente pode não utilizar esquemas, colocar os esquemas, utilizar com ou sem esquemas os esquemas do Datomic, com optionals, com maybes, sem maybes, sem optional. Dá para fazer tanta coisa que a gente vai analisar as vantagens e desvantagens de cada uma dessas abordagens e escolher um caminho de acordo com o que é mais utilizado aí fora.

Além disso, a gente vai ver que também certos pedaços de códigos são muito comuns no dia a dia das nossas queries e como extrair isso para regras que permitem que a gente crie queries cada vez mais complexas em cima de tudo isso que a gente trabalhou. Então as regras que a gente vai criar, as rules, são compostas, utilizam maneiras de binding de variáveis distintas e a gente vai fazer tudo isso nesse curso. Vamos começar.

Schemas e schemas - Definindo os schemas dos modelos

Vamos então começar o nosso curso. A gente vai criar um novo projeto. Assim como no curso anterior, esse projeto vai se chamar ecommerce. Eu vou criar um novo projeto, Clojure, a gente vai utilizar o Leinigen e vou dar next. Vou escolher o diretório onde eu vou colocar esse meu projeto, que vai ser aqui em datomic3, projeto, open, ecommerce. Na verdade, o meu diretório exato vai se chamar ecommerce aqui dentro. Finish.

Ele vai criar para mim esse diretório. Maravilha. O que eu quero fazer é trazer algumas coisas do curso anterior. Lembra, não vou trazer tudo, vou trazer só uma parte da infraestrutura que a gente foi utilizando. O que eu vou fazer? Eu já tenho baixado aqui para mim o projeto final do curso anterior. Se você não tem, não se preocupa. Nas atividades vai ter o link para você baixar o projeto anterior.

Vou abrir um editor de texto qualquer. Vou abrir o Sublime no meu caso. Dentro do Sublime vou abrir o diretório desse projeto. Assim a gente consegue explorar alguns arquivos.

Vamos lá. Dentro do IntelliJ, eu tenho o meu projeto, cujo diretório é crc, ecommerce e core. Dentro do core, lembra, a gente não precisa definir fun porque a gente não vai usar nenhuma função chamada fun porque não faz sentido nenhum. Mas a gente tem algumas coisas de projeto. Então vamos no projeto antigo.

Lembra, a gente tem que adicionar dependência do Datomic, olha a dependência do Datomic, da versão exata que eu estava usando. Vou copiar e vou colocar no meu project.clj a dependência do Datomic.

Lembrando, o IntelliJ pode perceber essa alteração e pedir para você recarregar o seu project.clj ou você vem no seu Leinigen e clica aqui em recarregar. Ele vai recarregar, ver se tem alguma coisa para baixar, etc.

Além do project.clj, a gente tem alguns arquivos no crc que a gente criou. Na verdade, você vai ver que teve vários, um para cada aula. O core não tinha nada demais, o db tem diversas funções para trabalhar com o banco e o model tem o nosso modelo para trabalhar com um novo produto ou uma nova categoria. Esses dois arquivos a gente vai utilizar. Então eu vou criar aqui um novo file, Ctrl+N, no meu caso é Command+N porque é Mac, Clojure namespace, vou criar o meu model, model.clj, no diretório ecommerce no namespace, então ecommerce.model.

Posso copiar tudo que está aqui, o novo-produto, a nova-categoria e o id. Fechei. Um novo arquivo, que é Clojure também. Novo Clojure, db é o nome do namespace. Criou aqui para mim. Posso copiar esse código daqui. Copiei e colei.

Daqui eu posso tirar algumas coisas. Tem muitos comentários que a gente foi criando à medida em que a gente criava o curso. Então várias dessas coisas eu poderia apagar. Eu vou deixar esse primeiro comentário, “mostrando um pouco os datoms” para que a gente possa ir explorando à medida em que a gente achar necessário.

Outras coisas aqui eu vou apagar, outras funções que a gente não utiliza mais eu vou apagar. Então todos-os-produtos-por-slug-fixo, esse aqui eu vou deixar, todos-os-produtos-por-slug-fixo. Aqui é por slug fixo, aqui é por slug normal. Aqui vamos ver. aqui são outros comentários. Vamos lá. Aqui mais comentários que eu posso apagar. Esse exemplo com forward, que a gente não está utilizando. Esse aqui é um exemplo com back. Alguns exemplos de resumos, que era a questão dos sets e do if. Duas queries soltas de uma vez só nessa de queries. Legal.

Então removi aqui os comentários. Tenho basicamente o código de diversas funções. Claro, o IntelliJ já está comentando para mim que tem várias coisas que a gente está definindo globalmente com defs do global dentro do namespace que não são utilizadas nesse projeto ainda. É verdade. Então o IntelliJ já dá várias dicas para a gente. Fechei. Estou com o meu projeto, estou com o db, estou com o model. O que falta?

Vamos pegar um exemplo final aqui, o aula6. Vou pegar aula6, copiar e criar aqui para a gente aula1 na verdade. Nossa aula1. Vou colar aqui. Mas vai ser a aula1.

Mas agora sim a gente vai trabalhar um pouco diferente. Primeira coisa. Lembra, talvez você tenha um banco já aí, talvez não, talvez você tenha apagado, talvez não. Não sei dizer. Lembra que a gente criou a função apaga-banco? A função apaga-banco remove o banco.

O que eu vou fazer? A primeira coisa de todas, para garantir que eu sempre que rode esse script está com o banco limpo, vai ser apagar o banco. Então vou apagar o banco primeiro de tudo. Depois eu abro uma conexão com esse banco, crio o esquema e aí eu posso sair adicionando várias dessas coisas. Lembra, estou adicionando aqui os eletrônicos, os esportes, imprimindo o resultado dessas inclusões.

Depois eu vou adicionar os produtos, atribuir as categorias e imprimir. Não vou adicionar camiseta e a dama. Tantas categorias quanto os produtos. Vou imprimir esses dois. Como eu vou só imprimir as categorias, vou pôr aqui direto imprime as categorias. Então eu estou imprimindo todas as categorias e todos os produtos.

Primeiro eu adiciono vários produtos e várias categorias, depois eu faça o resto. O que eu vou fazer é pegar esse código aqui de adicionar exemplos de dados para a gente e colocar num namespace próprio. Eu vou criar um namespace chamado sample, de dados de exemplos que eu vou utilizar. Eu vou pegar esses dados, vou copiar, cortar na verdade, pegar o meu db.

Olha, o esquema e o db eu gostaria já de jogar num arquivo diferente. Quando fizer sentido a gente pode jogar sim, não tem problema. Vou criar uma definição de uma função nova, que é cria-dados-de-exemplo. Tem que receber o quê? A conexão. E fazer tudo isso. Dou um paste aqui e faço tudo isso.

Então o cria-dados-de-exemplo passa a conexão, deve criar os dados de exemplo para a gente e a gente mostrar as categorias e os produtos. Isso que eu gostaria de fazer.

Os imports, os requests, já devem estar adequados. O request, eu tenho do db, do d. Mas eu tenho que tomar um cuidado. Dá uma olhada lá. A gente usa o nova-categoria e o novo-produto. Ambos estão no model, a gente não fez o require do model. Eu vou precisar fazer o require do model também. Então eu vou ter um require do model aqui.

Eu acho que agora está ok. Vou rodar aqui o meu REPL. E teoricamente acredito que a gente tenha aí o nosso projeto rodando com o banco iniciado do zero, porque a gente vai limpar. Para fazer isso, assim que ele inicializar o REPL para a gente, inicializou, a gente pode carregar esse arquivo inteiro ou carregar por partes. Eu vou carregar por partes na primeira vez.

Então Command+Shif+P ou Ctrl+Shift+P, rodei aqui o namespace, daqui a pouco ele vai falar que rodou. Opa. No such namespace db. Ele não achou aqui no próprio db. Não tem o próprio db. Verdade. Aqui é direto adiciona-categorias, aqui é direto adiciona-produtos. Aqui é direto, atribuir-categorias. E direto atribuir-categorias. Vou tentar rodar de novo então esse namespace aqui com os requires.

Mesmo erro. Linha 12. Calma aí, ecommerce.db. Mesmo cara aqui está falando que não tem o db. ecommerce.db not found. Vamos procurar db. Aqui não é. Então acho que agora faltou só recarregar esse arquivo. Vou recarregar esse arquivo.

adiciona-categorias não achou. Cadê o adiciona-categorias? Está aqui. Estou definindo fora de ordem, tenho que definir na ordem certa. Então isso daqui vem lá no fim. Vou jogar lá no fim. Salvei. Recarreguei. Maravilha. Agora vou rodar esse namespace aqui só para ter certeza. Está rodando o namespace. apaga-banco. Rodando o apaga-banco.

Opa. Não vai rodar o apaga-banco. Por que não vai rodar o apaga-banco? Porque o Guilherme não inicializou o banco. Entre um curso e outro, dou stop no banco. Maravilha. Estou no diretório do banco. O que eu faço? Rodo o meu transactor.

Agora eu vou rodar o transactor. Agora ele consegue conectar, senão ele não conseguia conectar. Vamos ver então. Esperar aqui. Quando ele terminar, conectar, abrir as conexões do nosso banco... Está abrindo. Abriu. Agora a gente pode rodar o apaga-banco. Apagou o banco. No meu caso o banco já existia.

Abre a conexão, cria o esquema, olha o esquema criado, cria os dados de exemplo. Só testar todas-as-categorias e todos-os-produtos estão lá. Maravilha. A gente tem tudo que a gente queria.

O que eu queria fazer agora era adicionar um pouco de esquema nisso tudo. A gente trabalhou sem esquemas até agora. Eu queria trazer um pouco daquele trabalho que a gente fez do Plumetic schema. Lembra? Vou lá no navegador, Plumetic, schema. A gente tem ali como a gente faz para utilizar o Plumetic schema.

Primeira coisa, como sempre, vai utilizar uma biblioteca, adiciona dependência. Vamos lá no project.clj, a gente vai adicionar, porque a gente vai sentir as dificuldades ou as vantagens do esquema, de adicionar esquema com o banco. Prismatic/schema 1.1.12. Salvei. Ele vai perceber ou não perceber. Eu recarrego. Depois de recarregar, eu tenho que reinicializar o REPL. Vou reinicializar o REPL para que ele use agora carregando os pacotes adequados. Então vou rodar de novo o REPL.

Posso fechar o meu project. E o que eu tenho que fazer é adicionar o esquema onde eu quiser.

Lembra, desce, a gente vai ver lá, olha, primeira coisa é a gente trazer o esquema. schema.core :as s. Vamos lá. Onde eu vou querer esquema? No meu ecommerce.db, no meu banco. Na hora de adicionar coisas no banco, eu vou querer receber um produto para adicionar um produto. A gente vai trabalhar com o produto para a gente ver o que acontece.

Então eu vou falar que eu tenho um schema.core :as s, de schema. O que a gente faz? Quando a gente vai adicionar um adiciona-produtos, o que a gente quer falar? Vou subir lá em cima para deixar mais claro. Depois do schema, a gente vai ter o adiciona-produtos. O adiciona-produtos pode receber o quê? Produtos.

O que é o produtos mesmo? É uma sequência de produtos. Então a gente precisa de um esquema que defina um produto para a gente. Lembra lá no curso de esquema? A gente tem lá o github alura cursos clojure schema. Vamos lá no exemplo do curso que a gente tinha. Opa. Não fui esperto porque aqui eu não procurei adequadamente. Mas schema. Está aqui clojure-schema. Maravilha.

No Alura Cursos do clojure-schema, a gente tinha feito uma aula em que a gente trabalhou diversas questões de schema. No src.hospital, a gente tem ali a aula5. E a aula5 faz diversas questões de schema. Por exemplo, define vários pacientes como mapa, define um paciente como sendo um número inteiro positivo, um nome, um plano e uma chave opcional.

No nosso caso a gente também quer definir um produto. Vamos definir um produto então. Para definir um produto eu gostaria de fazer o quê? Eu gostaria de fazer um def produto. O que o produto tem mesmo? O produto é uma schema de mapa que vai ter várias coisas. Vamos dar uma olhada lá no nosso Datomic o que um produto tem.

Tem nome, tem slug, tem preço, tem palavra-chave, id e categoria. Então tem várias coisas. Então ele nome, slug, preço, id, categoria e palavra-chave. O que acontece? Cada um desses aqui, cada um desses atributos, cada um desses valores que eu vou ter dentro de um mapa que representa o produto, vai ser de um tipo diferente. Então funcionava dessa maneira aqui. Lembra?

A gente tem que falar qual é o tipo. É um s/Str. Por exemplo, o nome é um s/Str. O slug também é um s/Str. O preço não, o preço é outra coisa. O preço tem que ser um número. Na verdade, tem que ser um BigDecimal. O que a gente tem ali? No Plumetic schema, na documentação dele aqui, a gente está no readme, a gente tem vários tipos.

Quando a gente for aqui em explorar documentação, a gente vai ver que tem os vários tipos. Tem um lugar que todos os tipos dele. Como o preço é um BigDecimal, eu vou colocar que ele é um BigDecimal.

O id é um uuid. Se ele é um uuid, eu vou ter que procurar exatamente o que ele é no schema. uuid é do tipo uuid. Quem é o tipo uuid mesmo? É um UUID, que está no nosso modelo. Ele é o java.util.uuid. É desse tipo aqui. Então ele é desse tipo aqui. java.util.uuid.

A categoria. Bom, a categoria, vamos deixar por enquanto sem categoria. Vamos primeiro fazer funcionar sem o relacionamento porque a gente ainda não definiu a categoria. E a palavra-chave? A palavra-chave, vamos dar uma olhada lá, é many, são várias strings. Então palavra-chave é uma sequência de strings. Fiz dessa maneira.

Lembra, o esquema, a definição dos esquemas, é como a gente coloca no nosso modelo. Então eu vou tirar daqui e jogar no nosso modelo. Está aqui. Então essa é a definição de um produto. Essa seria a definição do meu produto.

Claro, eu posso recarregar esse arquivo, ele vai falar que não existe o namespace. Por que não existe o namespace? namespace de schema, que a gente tem que importar lá do modelo também. Tem que dar um require. Aqui eu não tinha feito require. Então require schema. Beleza. Vamos recarregar. Recarreguei agora.

Se eu tenho esse produto, eu poderia fazer algum teste só para a gente garantir que está funcionando. O nosso modelo é o que a gente queria, justamente para cair no caso da categoria. Então vamos lá na nossa aula1.

A gente tinha o apaga-banco, conexão, cria-esquema, tudo mais. Depois de criar o esquema, antes de criar os dados de exemplo, eu queria testar então o nosso produto. Eu queria testar se alguma coisa é um produto válido. No cria-dados-de-exemplo, a gente tem aqui alguns modelos. Por exemplo esse modelo.

Isso daqui é um produto válido? Vamos testar. Só queria testar isso. Eu queria testar esse produto aqui, se ele é válido ou não. Vamos dar uma olhada lá. Lembra no hospital o que a gente tinha? A gente tinha diversas coisas que a gente fez, um monte de coisas que a gente tinha já feito na aula5. Mas bem no começo do hospital, acho que na aula1 ou aula2, a gente viu que a gente podia validar um tipo. A gente conseguia validar. Tem que o validate.

Eu quero validar do tipo long o número 15. Então eu podia chamar o s/validate. Então vou dar um pprint do s/validate. Aí eu falo qual é o tipo. O tipo é produto, mas o produto está num modelo, então model/produto. Cadê o meu produto? É esse aqui, que eu vou testar. Então eu vou dar um def computador só para a gente testar esse computador.

Então eu vou testar esse computador de acordo com o modelo produto. Se eu rodar o primeiro, eu não encontrei aqui o model porque eu não tinha importado provavelmente. Aqui eu vou importar. Vamos ver. model/produto. Vamos validar. namespace. Precisa importar o namespace aqui. Então schema.core :as s. Importei. Agora eu vou tentar validar. Não deu match. Por quê?

Preço, está faltando essa chave. Nome, está faltando essa chave. Está faltando todas as chaves, Guilherme. Não, a gente criou um novo-produto. Ele falou que está tudo faltando. Inclusive você tem uma chave que não deveria existir. produto/id. Calma aí, deveria existir produto/id.

Claro. Lembra, quando a gente falou de esquemas no passado, a gente estava usando schemas que tinham uma chave somente do tipo :id, :preço ou coisas do gênero. Agora o nosso produto, os nossos schemas ligados com o Datomic, todos têm um certo namespace. É :produto/id, :categoria/id. Tem um namespace dentro da chave. E é essa que é a diferença.

Quando eu criei agora o modelo baseado em como a gente trabalhava, repara que não era produto/nome, mas agora é produto/nome. Toda chave tem um namespace, tem um espacinho onde a gente está colocando, que é o produto/não sei o quê, produto/palavra-chave. Esses são os nomes das chaves que eu gostaria de ter.

Recarreguei esse arquivo. E aí eu posso tentar validar de novo. Tento validar. Ele fala que não bateu exatamente. palavra-chave não está lá. Verdade. palavra-chave é opcional. Lembra, palavra-chave para a gente é opcional. Vários produtos não têm palavra-chave. Então eu gostaria que isso aqui fosse opcional. Lembra como eu faço opcional?

Na última aula do hospital, a gente tinha um exemplo opcional. s/optional-key. Então essa aqui é uma chave opcional. Então s/optional-key. Vou alinhar aqui o código. Posso recarregar esse arquivo e rodar de novo para tentar validar. Tentei validar. Falou que está ok. s/validate deu redondinho. Esse deu redondinho por enquanto.

E se eu pegasse esse computador aqui e tentasse colocar um outro valor lá dentro? Por exemplo, tenta dar um assoc no produto/preço do valor 76. Vou tentar trocar o preço por 76. Rodei. Agora sim falou que não matchei o schema. Não está batendo. Se não está batendo, maravilha, é o que eu quero, que não batesse mesmo.

Então esse aqui está ok. Eu posso copiar e mostrar que esse aqui, assoc computador :produto/preço 76. Por quê? 76 é um número, não é um BigDecimal, é um inteiro. Então ele vai reclamar que produto/preço não é BigDecimal. Então está ok.

Então a validação do nosso produto válido está joinha, de um produto completo. Completo significa nome, slug, preço, id, opcionalmente palavra-chave. O que está faltando? A categoria. Está faltando a gente definir a categoria. O que a categoria tem que ter mesmo? Só a gente descer. Ela tem que ter o id e o nome. id e nome a gente sabe fazer.

Ela é um categoria/id, que é um java.util.UUID, e ela tem que ter um categoria/nome, que é um s/Str. Não fiz com validações mais complexas. Claro, à medida em que você vai evoluindo o seu sistema, você pode ter validações mais complexas, você pode ter esquemas mais complexos. Para a gente por enquanto isso aqui está sendo suficiente. Categoria e produto.

Podemos validar uma categoria? Vamos lá. Vamos pegar esse aqui, eletrônicos, e eu vou querer validar. Vamos fazer separadinho. pprint, s/validate, categoria, eletrônicos. Faltou carregar. Esse aqui botei de novo. E aqui a categoria deveria ser ok. Mas ele não achou model/categoria. Validou. id e nome. Joinha. Está parecendo ok por enquanto. Quer dizer, o meu produto e a minha categoria têm que ter isso.

Só que, lembra, um produto tem que ter opcionalmente categorias. Por quê? Por enquanto eu salvei ele sem categorias e de repente eu posso querer colocar uma categoria lá dentro. Categoria é uma só. Qual é a chave da categoria mesmo? Você lembra? Lá no nosso banco de dados a gente fala, é a chave do Datomic que a gente estava usando para categoria, que era produto/categoria.

Lá no meu s/optional :produto/palavra-chave eu vou ter um produto/categoria, que é do tipo, advinha, categoria. Só que tem um cuidado a tomar. A categoria é opcional. Se a categoria é opcional, s/optional-key. Então agora tem isso daqui. Vamos lá. Realinhei. Recarreguei.

Olha, o nosso produto continua válido. Agora, se eu pegar o meu produto com uma categoria, se eu der um assoc aqui no meu computador que a categoria dele seja eletrônicos, também deveria funcionar. Funcionou. Se fosse categorias, aí daria caca, porque não é categorias, é categoria. Se fosse categoria com número em vez de uma categoria para valer, também tem que dar caca. Então é esse daqui.

Então a gente está com o nosso esquema adequado. Vou extrair uma função aqui, testa-schema, só para a gente testar o esquema certinho. Vamos colocar todo mundo para dentro. Coloquei. A gente pode chamar o testa-schema. Opa. Faltou definir. Vou definir. E aí rodei o testa-schema para ficar mais limpo para a gente.

Então o testa-schema está maravilha. Tem uma última coisa que eu quero fazer então. Eu queria fazer que, quando a gente chama a função de adicionar, eu crio esquema... desculpa, cria-dados-de-exemplo chama o adiciona-categorias e o adiciona-produtos, a gente recebo categorias e produtos. Então o que a gente tem que fazer? A gente tem que nesses lugares alterar.

Eu vou fazer primeiro só o da categoria, depois a gente faz dos produtos, que vai ter problema. Então adiciona-categorias significa s/defn, porque a gente vai usar o schemas, e a gente vai falar que a categorias é do tipo sequência de model/Categoria. Então tem que ser várias categorias.

Tem que tomar um cuidado. Por quê? Lembra que vai estar desativada a validação do esquema por padrão? Por padrão a validação do esquema está desativada. Você pode forçar através de um s/validate, que foi o que a gente fez. Se eu quero ativar a validação, como eu faço mesmo? A gente tem aqui um set function validation. Por padrão invocar uma função, a gente terá validação efetuada.

Então eu vou colocar logo de cara. Rodei. Forcei validação. Vou tentar chamar o cria-dados-de-exemplo... Não tinha conexão ainda. Vamos rodar tudo do zero. Abrir o banco, cria o esquema, testei o esquema aqui, cria-dados-de-exemplo. Criou os dados de exemplo, isso é, está criando as nossas categorias e utilizando esse meu schema.

Então a gente está com o schema funcionando. Mas daqui a pouco a gente faz isso para os produtos e vê os problemas que vão aparecer

Schemas e schemas - Find specs e schemas

Agora que a gente já criou o cria-dados-de-exemplo, adiciona-categorias, recebendo então uma sequência de categoria, eu queria que também a adição de produtos, o adiciona-produtos, também recebesse aqui uma sequência de produtos, model/produto. A mesma coisa na segunda variação, também é um model/produto.

Para fazer isso eu vou fazer um s/defn. Posso carregar esse arquivo para ter certeza que está ok. Maravilha. Vou começar do zero aqui. Carregando o meu namespace, acertando a validação, apagando o banco, criando o banco novo. Agora que a gente tem o banco novo, vou testar o esquema só para ver se está ok. Opa. testa-schema não defini. testa-schema. Maravilha. Cria o dados.

Quando eu tento criar dá caca. O que acontece? O adiciona-produtos está sendo chamado com algo que não bate com o esquema, o input, a entrada do adiciona-produtos está sendo chamado com algo que não dá certo. Linha 25. É o cria-dados-de-exemplo mesmo. No cria-dados-de-exemplo o adiciona-produtos está adicionando um produto que não tem slug. É verdade. A calculador não tinha slug.

Lembra, o Datomic, quando diferente esquemas do Datomic, cada um desses idents não tem nada a ver um com o outro. Então eu posso ter uma entidade que tem só slug de produto, uma entidade que tem palavra-chave e id, uma entidade que tem categoria e preço. Posso ter uma entidade que tem slug de produto e nome de categoria. Nada me impede de misturar isso.

Essa palavra que define o namespace da nossa palavra-chave, do keyword, não significa que existe 100% de conexão, obrigatoriedade ou algo do gênero. Não é isso que o Datomic está fazendo. Só significa que, se existir esse identificador dentro de uma entidade, essas são as regras que esse identificador, ou que esse valor, vai ter que seguir. Se existir esse identificador, essas são as regras. E por aí vai para cada uma das entidades.

No meu caso a entidade não tem slug. Para o Datomic era ok, mas para o nosso modelo, se a gente abrir o nosso modelo, isso não é ok. Precisa ter slug. Então o que a gente vai fazer? Por enquanto vamos tirar fora. Não quero produto sem slug. É isso mesmo, não quero. Vou tirar fora calculadora. Posso recarregar esse arquivo, posso tentar criar os dados de exemplo de novo. Maravilha. Funcionou.

Agora que a gente fez o adicionar dos dois lados e a gente discutiu essa questão da obrigatoriedade, que está indo de acordo com o teu esquema prismatic e não do esquema do Datomic, então você tem esses dois esquemas, o que eu quero fazer agora é trazer todas as categorias. Eu tento trazer as categorias e elas vêm. Vamos aplicar o esquema em todas-as-categorias. s/defn todas-as-categorias retorna uma sequência de model/Categoria. Recarrego o arquivo e torço para funcionar.

Lembra, cada vez que eu coloco cria-dados-de-exemplo, eu estou adicionando dois iguais lá, eletrônicos e esporte. Então cada vez vai ter mais. Mas eu quero só trazer as categorias. Vamos testar. Tento e não funciona. Agora não é mais um input, agora é o output. A saída de todas-as-categorias está com problema. O que ele está falando?

A saída de todas-as-categorias não está batendo com o esquema de um vetor persistente. Por que não? Vamos dar uma olhada. A saída não é um vetor? Não é. Olha só que estranho. Até é ou pode ser. Vamos dar uma olhada. todas-as-categorias. A gente quer que seja um vetor, uma sequência, de categorias. Mas olha o que está sendo. Está sendo um vetor de vetor de mapa. Em vez de ele devolver um vetor de mapas, onde cada um é uma categoria, categoria1, categoria2, categoria3, que é o que eu queria, ele está devolvendo isso aqui. categoria1, outro vetor, categoria2, outro vetor, categoria3, outro vetor e por aí vai. Por quê?

Vamos dar uma olhada. O que acontece é o seguinte. Imagina que a primeira versão do Datomic, o find, a primeira de todas, find era várias coisas. Você poderia falar find para mim o nome da categoria ou o nome do produto e um preço. O que ele retornaria para mim? Por padrão, como você usa padrão do Datomic, find várias coisas, por padrão ele devolve para a gente o nome e o preço do primeiro resultado encontrado, o nome e o preço do segundo resultado encontrado, o nome e o preço do terceiro resultado encontrado e por aí vai.

Então ele automaticamente coloca tudo que você tem dentro de um find dentro de uma sequência. Eles vão chamar de dupla. O tipo específico que está sendo usado por trás eu acredito que seja um vetor, mas eu não sei, porque teria que executar, descobrir o tipo, etc. E não importa para a gente. O que importa aqui é que a apresentação está sendo como vetor, se é lazy, se é eager etc. são outras questões. Mas para a gente está sendo trazido dessa maneira. Por quê?

Por padrão, quando você faz um find, ele traz assim. Se você fizer um find de um valor só, find de nome, o que ele vai fazer? Ele vai trazer isso aqui. Você fala que não era bem isso que queria, o que queria era isso, sem esse cara, sem esse cara, sem esse cara. O que eu queria era tirar esses vetorezinhos daqui. Por quê? Porque cada um desses daqui já é a categoria. Então teria um vetor das categorias.

E aí está o curioso. Como por padrão historicamente o find traz vários e por padrão o Datomic já coloca numa sequência, então por padrão a gente não coloca nada e ele já faz isso. Se eu quiser tirar a sequência, o que eu tenho que fazer? Eu tenho que colocar uma sequência. É o inverso. Percebe que fica estranho? Mas com certeza é uma questão de compatibilidade com versões antigas e com a definição de como isso seria, do que era mais importante na época.

Se hoje o mais usado é com ou sem, eu não sei dizer, vai depender de cada empresa, de cada uso. Pessoalmente me parece fazer mais sentido usar quase sempre com os [ aqui, porque eu não vou querer um [ nesse daqui. Mas tem queries em que você quer, em que você vai utilizar, aí você tira os [. Depende do que você quer. Vê o resultado da tua query, se faz sentido, se você quer trabalhar com essa seleção dos elementos escalares aqui assim e colocar eles num vetorzinho ou se você quer tirar.

Aí eu vou tentar. Não estou dizendo que vai funcionar. O que eu vou fazer? Eu tirar isso daqui só para a gente ver o resultado. Tirei isso daqui. Recarreguei. Vamos ver o resultado. O resultado é uma única categoria. É verdade que dentro de um vetor veio só uma. E aí não foi vetor de vetor, mas veio só uma. Por quê? Porque uma das questões é que era tão comum trazer só uma, você pedir só uma quando você quer só uma, você tem certeza que vem só uma.

Se você tem certeza que vem só uma, você pode colocar entre [] que só veio uma, apesar de ter mais. Apesar de ter mais, ele trouxe só uma. Qual que ele trouxe? A primeira? Não existe ordem aqui. Ele trouxe o que veio. Poderia ter sido outra coisa. Ele trouxe o que veio aqui. Então não era exatamente isso que eu queria. O que eu queria era entre [], porque [] vai tirar os [ que eu queria tirar, lembra do inverso, mas eu quero dizer para ele também que não é só uma que eu quero, eu quero todas.

... Eu quero todas. Agora eu recarrego. E eu rodo. E aí você percebe que ele trouxe como a gente queria, uma categoria, duas categorias. E agora sim é um vetor de mapas. Agora é o que eu queria. O que eu vou fazer agora? Eu tenho o meu vetor de mapas. Agora sim eu posso botar que retorna um model/Categoria. Recarregar o meu arquivo. Rodar esse cara aqui. E aí ele fala um outro erro.

Agora é o erro da saída ainda, mas um erro mais simples. db/id não poderia estar na sua categoria. Como assim? Dá uma olhada. db/id é retornado sempre que a gente traz uma entidade completa do banco. Uma entidade completa do banco vai ter o quê? Vai ter os valores atribuídos a ela e o id identificador dela no próprio banco. Não é o id único que a gente gerou, que é o uuid, é o db/id, o próprio do banco. E aí você vai ter que tomar uma decisão.

Deixa eu apagar aqui esse pedaço. O resultado está vindo no formato que a gente quer, mas a gente tem que tomar uma decisão. Na representação de categoria do meu modelo eu vou ter o db/id sim ou não? Em geral não faz sentido ter o db/id dentro da sua representação do modelo de categoria. Você poderia falar que sim, opcionalmente, como fosse, não tem problema, em geral não faz. Então o que a gente acaba tendo?

Nesse todas-as-categorias, vou tirar aqui o todas-as-categorias, isolar, que são coisas que a gente utiliza. Em todas-as-categorias, o que a gente vai fazer? Depois que a gente buscou todas essas categorias, o que a gente vai fazer é transformá-las. transformar-de-datom-para-entidade. Vou chamar de entidade. De Datomic eu vou transformar em entidade. Vai aqui na próxima linha para ficar mais alinhadinho.

Lembra daquela história da questão do imperativo? Muitas vezes você vai ver só o datom-para-entidade, alguma coisa do gênero. Depende da empresa, de como você está trabalhando, o próprio Datomic, você vai ver vários no imperativo e por aí vai.

Então define essa função. datomic-para-entidade recebe o quê? Várias entidades, várias entidades. E ela vai fazer o quê? Vai passar por todas essas entidades, removendo. Então ela vai passar um lambda, desassocia dessa entidade específica, que é um mapa, a :db/id. Então eu estou tirando o db/id de todas essas entidades. É isso que eu estou fazendo.

Mas, repara, essa daqui é uma “versão simples, que não faz recursivamente”. Uma versão mais complexa recursiva, que no nosso caso por enquanto não precisa, é assim. Se tiver um mapa embaixo que tem db/id, tem que entrar nesse mapa e tirar o db/id de lá também. Percebe? Faz sentido. Então você teria que fazer isso recursivamente.

Vamos recarregar esse arquivo. Opa. def. Recarrego. Beleza. Vamos ver se todas-as-categorias está funcionando. Todas as categorias. Estão lá as quatro categorias para a gente.

Então a gente foi capaz de adicionar produtos e listar as categorias. Vamos listar os produtos daqui a pouco utilizando tudo que a gente está vendo.

Sobre o curso Datomic: Schemas e Regras

O curso Datomic: Schemas e Regras possui 158 minutos de vídeos, em um total de 31 atividades. Gostou? Conheça nossos outros cursos de NoSQL em Data Science, ou leia nossos artigos de Data Science.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda NoSQL acessando integralmente esse e outros cursos, comece hoje!

Plus

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$85
à vista R$1.020
Matricule-se

Pro

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$120
à vista R$1.440
Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas