0Pricing
Scala for Backend Engineering & Functional Programming · Aula

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].option

Transmitindo 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].stream

Controlando 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

  1. Conectando com um transator
  2. Executando consultas
  3. Inserções e atualizações
  4. Compondo transações
← Voltar para Scala for Backend Engineering & Functional Programming