Executando consultas
Leia linhas em classes de caso.
Executando consultas é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.
O interpolador sql
O interpolador de strings sql do Doobie é o núcleo das consultas. Ele analisa seu SQL e transforma valores Scala incorporados em parâmetros associados com segurança.
Os valores interpolados tornam-se marcadores JDBC ?, portanto não há injeção de SQL nem configuração manual de PreparedStatement.
import doobie.implicits._
val minAge = 18
val frag = sql"select name from users where age >= $minAge"De Fragment para consulta
Uma expressão sql"..." é um Fragment. Para executá-la como uma leitura, você chama .query[A], escolhendo o tipo de linha A.
O Doobie usa uma classe de tipos Read[A] para mapear as colunas do resultado para A, com suporte a tipos primitivos, tuplas e classes de caso.
case class User(name: String, age: Int)
val q: Query0[User] =
sql"select name, age from users".query[User]unique, option e to
Um Query0[A] oferece diferentes acumuladores. .unique espera exatamente uma linha, .option espera zero ou uma, e .to[List] coleta todas as linhas.
Cada um retorna um ConnectionIO que você executará posteriormente com .transact.
val one: ConnectionIO[User] = q.unique
val maybe: ConnectionIO[Option[User]] = q.option
val all: ConnectionIO[List[User]] = q.to[List]Mapeando linhas para classes de caso
O Doobie deriva automaticamente instâncias de Read para classes de caso quando cada campo possui um mapeamento de coluna. A ordem das colunas deve corresponder à lista de seleção.
Isso permite selecionar diretamente para tipos de domínio ricos, sem código repetitivo para analisar as linhas.
case class Account(id: Long, email: String, active: Boolean)
val accounts =
sql"select id, email, active from accounts"
.query[Account].to[Vector]Consultas parametrizadas
Cada valor Scala interpolado é associado como parâmetro usando sua instância de Put. Você pode interpolar quantos valores quiser, inclusive em posições diferentes.
Como eles são associados, e não concatenados, os tipos são verificados e a injeção é impossível.
def findByEmail(email: String): ConnectionIO[Option[Account]] =
sql"select id, email, active from accounts where email = $email"
.query[Account].optionTransmitindo resultados grandes
Para grandes conjuntos de resultados, use .stream para obter um Stream[ConnectionIO, A] do fs2. As linhas são buscadas sob demanda com um cursor no servidor, mantendo o uso de memória limitado.
Combine-o com os combinadores do fs2 para processar milhões de linhas incrementalmente.
import fs2.Stream
val s: Stream[ConnectionIO, Account] =
sql"select id, email, active from accounts"
.query[Account].streamControlando o tamanho da busca
O tamanho padrão da busca do cursor pode carregar tudo de uma vez em alguns drivers. .streamWithChunkSize(n) define o tamanho de busca do JDBC para que o cursor busque n linhas a cada ida e volta.
Ajustar esse valor equilibra as idas e voltas com o uso de memória.
val s =
sql"select id, email, active from accounts"
.query[Account]
.streamWithChunkSize(512)Colunas opcionais e possibilidade de nulo
Colunas que aceitam nulo são mapeadas para Option[A] no seu tipo de linha. Se uma coluna puder ser NULL, você deverá lê-la como um Option; caso contrário, o Doobie lançará um erro ao encontrar um valor nulo.
Isso torna a possibilidade de nulo explícita e segura quanto aos tipos na fronteira.
case class Person(id: Long, nickname: Option[String])
val ps =
sql"select id, nickname from people".query[Person].to[List]Construindo SQL com Fragmentos
Valores Fragment são compostos com ++, permitindo montar consultas a partir de partes e, ao mesmo tempo, manter os parâmetros associados.
O interpolador fr constrói um fragmento com um espaço ao final, o que é útil para unir cláusulas.
val base = fr"select id, email, active from accounts"
val where = fr"where active = $${true}"
val q = (base ++ where).query[Account]Cláusulas WHERE dinâmicas
Os auxiliares Fragments do Doobie constroem cláusulas condicionais. Fragments.whereAndOpt combina filtros opcionais, incluindo apenas os que estão presentes.
Essa é a maneira idiomática de construir consultas de pesquisa dinâmicas e seguras.
import doobie.util.fragments._
val emailOpt: Option[String] = Some("a@b.com")
val filter = whereAndOpt(emailOpt.map(e => fr"email = $e"))
val q = (fr"select id, email, active from accounts" ++ filter)Verificando consultas no momento da compilação
A análise check do Doobie executa uma consulta com base no esquema do banco de dados para verificar se os tipos e as quantidades de colunas correspondem aos seus tipos Scala.
Quando usada em testes, ela detecta alterações incompatíveis no esquema antes que cheguem à produção.
import doobie.scalatest._
// inside a spec mixing in IOChecker
check(sql"select id, email, active from accounts".query[Account])Verificação rápida
Escolha o acumulador adequado.
Recapitulação
O interpolador sql constrói Fragments parametrizados; .query[A] os transforma em um Query0[A] mapeado por meio de Read[A].
Escolha .unique, .option, .to[List] ou .stream para acumular linhas. Use Fragments para cláusulas dinâmicas e check para validar a consulta em relação ao esquema.
Perguntas Frequentes
A aula “Executando consultas” é grátis?
Sim — o texto completo de “Executando consultas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.
O que vou aprender em “Executando consultas”?
Leia linhas em classes de caso. Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?
Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Executando consultas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?
Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Conectando com um transator
- Executando consultas
- Inserções e atualizações
- Compondo transações