DEV Community

Cover image for Usando a Biblioteca Exposed
Lissa Ferreira for Kotlinautas

Posted on • Updated on

Usando a Biblioteca Exposed

Kotlinautas

Esse conteúdo é oferecido e distribuído pela comunidade Kotlinautas, uma comunidade brasileira que busca oferecer conteúdo gratuito sobre a linguagem Kotlin em um espaço plural.

capa Kotlinautas

O quê é um ORM?

ORM (Mapeamento de Objeto Relacional) é uma maneira de mapear dados de um banco de dados, em objetos de uma aplicação. Como se fosse uma ponte entre classes da nossa aplicação, e o banco de dados da aplicação.

ORM's servem principalmente para facilitar a comunicação entre uma aplicação e seu banco de dados. Facilitando processos de leitura, escrita, atualização e remoção de dados.

O quê é Exposed?

Exposed é a biblioteca oficial de ORM para Kotlin, criada pela própria JetBrains. Uma de suas principais vantagens é poder usar diferentes bancos de dados, e poder trocar qual banco você está usando de maneira fácil. A lista de bancos de dados atualmente suportada pelo Exposed é:

  • H2
  • MySQL
  • MariaDB
  • Oracle
  • PostgreSQL
  • SQL Server
  • SQLite

O quê vamos criar?

Vamos criar um sistema de cadastro de planetas. Onde poderemos inserir informações sobre um planeta, e essas informações serão inseridas em um banco de dados. Com isso, poderemos usar a Exposed para conectar a nossa aplicação, á um banco de dados que desejarmos.

Criando o projeto

Abra seu IntelliJ no menu inicial e clique em New Project:

botão New Project no menu inicial do IntelliJ

Depois, selecione a opção Kotlin DSL build script, selecione também a opção Kotlin/JVM, e opicionalmente remova a primeira opção Java. Essa opção não vai mudar em nada, pois ela dá suporte do Gradle á linguagem Java, mas apenas iremos usar Kotlin.

Após isso, clique em Next e escreva o nome do projeto e a localização na sua máquina. Essas duas opção são completamente pessoais, caso não tenha nenhuma ideia, coloque algo como exposed apenas como identificação.

Agora, com o projeto aberto, vá ao aquivo build.gradle.kts e adicione as dependências da Exposed, com a seção dependencies ficando assim:

dependencies {
    implementation(kotlin("stdlib"))
    implementation("org.jetbrains.exposed:exposed-core:0.33.1")
    implementation("org.jetbrains.exposed:exposed-dao:0.33.1")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.33.1")
    implementation("com.h2database:h2:1.4.199")
    implementation("org.slf4j:slf4j-api:1.7.5")
    implementation("org.slf4j:slf4j-simple:1.6.4")
}
Enter fullscreen mode Exit fullscreen mode

Agora, clique no elefante no canto superior direito para carregar as alterações no Gradle.

Elefante do Gradle no canto superior direito

Após isso, poderemos começar a programar. Você pode criar um arquivo em src/main/kotlin/ chamado main.kt para ser o arquivo principal da aplicação.

Mas com qualquer nome de arquivo, como você irá usar a Exposed, sempre se lembre de importar a Exposed no começo do arquivo:

import org.jetbrains.exposed.sql.*
Enter fullscreen mode Exit fullscreen mode

Usando a Exposed

Primeiro, vamos precisar criar um objeto que irá representar uma tabela em nosso banco de dados, e dentro desse objeto inserir as colunas do nosso banco (como propriedades). Isso pode ser feito da seguinte maneira:

import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction

object Planetas: Table(){
    val nome = varchar("nome", 30)
    val massa = double("massa")
    val solido = bool("solido")
}
Enter fullscreen mode Exit fullscreen mode
  • Usamos a palavra object para criar o objeto, colocamos o nome da tabela Planetas, e o tipo da variável, que é um tipo da Exposed, Sendo Table;
  • Dentro do objeto, criamos três variáveis, sendo nome, massa, e solido. nome irá guardar o nome do planeta, massa irá guardar a massa do planeta comparada á terra e solido irá determinar se o planeta é sólido ou não;
  • Para determinar essas variáveis, usamos tipos de dados de um banco de dados, como varchar, double, e bool;

Após isso, podemos criar a nossa função main. Dentro dela, vamos primeiramente conectar ao banco de dados. Isso pode ser feito com a função Database.connect dessa maneira:

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")
}
Enter fullscreen mode Exit fullscreen mode
  • Estamos usando o banco de dados H2. Um banco de dados Java, que pode funcionar apenas na memória. Vamos usar esse banco de dados pois a cada vez que rodarmos o programa, teremos um novo banco totalmente zerado. Com isso você ficará livre para testar o banco, criando, lendo, editando e removendo dados;
  • Para fazer essa conexão, tivemos que passar um texto que representa esse banco. Caso você queira mudar o banco, você apenas irá precisar mudar esse texto;

Agora precisamos inserir a tabela Planetas que criamos no banco. Isso pode ser feito de maneira completamente automática usando a função SchemaUtils.create. Essa função pode ser usada da seguinte maneira:

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
        SchemaUtils.create(Planetas)
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Usamos um bloco transaction pois toda conexão ao banco (escrita, leitura, edição e remoção) precisa estar dentro de um bloco transaction;
  • Passamos ao SchemaUtils.create o nosso objeto Planetas. Com isso, essa tabela será criada no banco de dados;

Agora, vamos criar um bloco while (true) onde iremos executar um mesmo trecho de código eternamente, onde iremos ler o nome, massa e se o planeta é sólido ou não, vamos enviar esses dados ao banco de dados, e também mostrar todas as linhas do banco na tela.

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
        SchemaUtils.create(Planetas)
    }

  while (true){

  }
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos usar a função readLine para pegar os dados da linha de comando, mostrando na tela pergunta por pergunta:

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
        SchemaUtils.create(Planetas)
    }

  while (true){
        print("Insira o nome do planeta: ")
        val nomePlaneta = readLine().toString()

        print("Insira a massa do planeta: ")
        val massaPlaneta = readLine().toString().toDouble()

        print("O planeta é sólido? [sim/não]: ")
        val solidoPlaneta = readLine() == "sim"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • na variável nomePlaneta apenas transformamos o texto escrito na linha de comando em String com .toString();
  • na variável massaPlaneta primeiro transformamos o texto escrito em String, e depois transformamos essa String em Double. Para assim obtermos o número decimal da massa do planeta em relação á terra;
  • na variável solidoPlaneta testamos se o texto escrito é igual á "sim". se essa condição for verdadeira, o planeta é sólido. Se não, o planeta não é sólido;

Agora vamos executar a transação para inserirmos esses dados no banco:

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
        SchemaUtils.create(Planetas)
    }

  while (true){
        print("Insira o nome do planeta: ")
        val nomePlaneta = readLine().toString()

        print("Insira a massa do planeta: ")
        val massaPlaneta = readLine().toString().toDouble()

        print("O planeta é sólido? [sim/não]: ")
        val solidoPlaneta = readLine() == "sim"

    transaction {
      Planetas.insert {
        it[nome] = nomePlaneta
        it[massa] = massaPlaneta
        it[solido] = solidoPlaneta
      }
    }
  }

}
Enter fullscreen mode Exit fullscreen mode
  • Para inserirmos esses dados, podemos usar a função Planetas.insert, informando o valor de cada coluna do banco com it[COLUNA] = valor.

Agora já conseguimos escrever dados no banco. Por fim, vamos pegar todos os dados do banco, e mostrar na tela. Mostrando que realmente conseguimos escrever os dados. Primeiro, vamos pegar todas as linhas da tabela Planetas:

...

fun main(){
    Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
        SchemaUtils.create(Planetas)
    }

  while (true){
        print("Insira o nome do planeta: ")
        val nomePlaneta = readLine().toString()

        print("Insira a massa do planeta: ")
        val massaPlaneta = readLine().toString().toDouble()

        print("O planeta é sólido? [sim/não]: ")
        val solidoPlaneta = readLine() == "sim"

    transaction {
      Planetas.insert {
        it[nome] = nomePlaneta
        it[massa] = massaPlaneta
        it[solido] = solidoPlaneta
      }
    }

    transaction {
      val planetasSalvos = Planetas.selectAll()
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos percorrer por todo essa lista de dados, e mostrar na tela planeta por planeta usando um .map:

...

fun main(){
  Database.connect("jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1;", "org.h2.Driver")

    transaction {
      SchemaUtils.create(Planetas)
    }

  while (true){
    print("Insira o nome do planeta: ")
    val nomePlaneta = readLine().toString()

    print("Insira a massa do planeta: ")
    val massaPlaneta = readLine().toString().toDouble()

    print("O planeta é sólido? [sim/não]: ")
    val solidoPlaneta = readLine() == "sim"

    transaction {
      Planetas.insert {
        it[nome] = nomePlaneta
          it[massa] = massaPlaneta
          it[solido] = solidoPlaneta
      }
    }

    transaction {
      val planetasSalvos = Planetas.selectAll()

      planetasSalvos.map {
        if (it[Planetas.solido]){
          println("Planeta ${it[Planetas.nome]} tem ${it[Planetas.massa]} massas terrestres e é sólido")
        }else{
          println("Planeta ${it[Planetas.nome]} tem ${it[Planetas.massa]} massas terrestres e não é sólido")
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Dentro de um map, percorrermos elemento por elemento, e para nos referirmos ao elemento atual, podemos usar a variável it. e dentro desse it podemos pegar os valores de cada linha, podendo assim mostrar na tela;

Agora, executando esse programa, poderemos ver na prática como criamos um código que pode inserir e ler dados de maneira dinâmica:

Insira o nome do planeta: Mercúrio
Insira a massa do planeta: 0.1
O planeta é sólido? [sim/não]: sim
Planeta Mercúrio tem 0.1 massas terrestres e é sólido
Insira o nome do planeta: Vênus
Insira a massa do planeta: 0.9
O planeta é sólido? [sim/não]: sim
Planeta Mercúrio tem 0.1 massas terrestres e é sólido
Planeta Vênus tem 0.9 massas terrestres e é sólido
Enter fullscreen mode Exit fullscreen mode

Update e Delete

Duas operações que não usamos foram a Updatee Delete. Essas duas são muito parecidas em seu uso na Exposed. Pois nas duas é (quase sempre) necessário usar um parâmetro WHERE para definir quais linhas desejamos mudar/remover. Por exemplo, podemos fazer um Update com WHERE colocando a condição como argumento da função, e a alteração em si no corpo. Dessa maneira:

transaction {
  Planetas.update({ Planetas.nome eq "teste" }){
    it[Planetas.nome] = "Vênus"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Colocamos a condição entre {} como argumento da função, e no corpo alteramos a linha diretamente;

E para o Delete podemos fazer a mesma coisa, mas agora apenas precisamos colocar a condição:

transaction {
  Planetas.deleteWhere { Planetas.nome eq "teste" }
}
Enter fullscreen mode Exit fullscreen mode

Usando outros bancos de dados

Caso você queira usar os outros bancos de dados que a Exposed suporta, você pode ver a lista de URL's de conexão de diferentes bancos. Essa lista pode ser acessada clicando aqui

Finalização

Nesse artigo você aprendeu como usar de forma básica a biblioteca Exposed, para escrever, ler, editar e remover dados de um banco.

Muito obrigada por ler ❤️🏳️‍⚧️ e me segue nas redes, é tudo @lissatransborda 👀

Oldest comments (0)