DEV Community

Pedro Cardozo
Pedro Cardozo

Posted on

ORM's x Query Builder's x Raw SQL

Alt Text

Fala pessoal 👋 , dessa vez vamos falar sobre Raw SQL, Query Builder e ORM's! Bom, como todos sabem o uso de banco de dados é algo muito comum na vida de um DEV, e com isso surgem inúmeras formas de se trabalhar com os bancos. Meu objetivo nesse post é falar sobre as diferenças, pontos positivos e negativos de cada approach.

O que é Raw SQL ?

De forma resumida: é quando você escreve a query nativa em SQL.

Quando a sua aplicação tem conexão com o banco de dados ela possui um canal de comunicação, onde ela pode enviar as queries nativas feitas em SQL. Basicamente, Raw SQL é a maneira mais low-level que sem para falar com o seu banco (escrevendo as queries em SQL). Veja o exemplo a baixo:

const express = require('express');
const client = require('./db');

const app = express();

app.get('/', async (req, res) => {
    const result = await client.query(`SELECT * FROM "Users"`)
        .then(result => result.rows)
        .catch(err => console.error(err));

    res.send(result);
}); 

app.listen(3000, () => console.log('Running on PORT 3000'));
Enter fullscreen mode Exit fullscreen mode

Raw SQL

Vantagens

Aproveitar recursos nativos do SGBD.

Com as queries nativas a aplicação tem mais liberdade para utilizar os recursos nativos que cada SGBD tem a oferecer.

Performance.

Raw Queries tendem a ser mais performáticas por não possuírem abstração e nenhum processo de conversão de código orientado a objeto em SQL.

Desvantagens

SQL Injection.

Alt Text

Exato meus queridos, um dos maiores problemas quando falamos de Raw Queries é o famoso SQL Injection, isso ocorre pelo fato da não tratativa dos input's da aplicação, existem diversas soluções para corrigir esse problema. Mas para entendermos melhor, Olhe o exemplo abaixo:

const express = require('express');
const client = require('./db');

const app = express();

app.get('/', async (req, res) => {
    const result = await client.query(`SELECT * FROM "Users" WHERE name = ${req.query.name}`)
        .then(result => result.rows)
        .catch(err => console.error(err));

    res.send(result);
}); 

app.listen(3000, () => console.log('Running on PORT 3000'));
Enter fullscreen mode Exit fullscreen mode

Hmmmm ...🤔 , interessante, agora olhe um exemplo de uma requisição mal intencionada:

Alt Text

Como vocês podem ver, no query param foi passado o nome e uma instrução SQL "Aonde ocorre o ataque" o nosso retorno acabou devolvendo alguns dados que não deveriam ser retornados. Existem varias maneiras de contornar esse tipo de problema, mas a ideia é demonstrar o que pode acontecer sem a tratativa dos input's e o risco potencial.

Tipagem e Syntax highlighting.

Quando inserimos a nossa query em SQL no código ela fica interpolada por um string da seguinte maneira SELECT * FROM "Users" o que acontece é que caso tenha algum erro de digitação você não irá conseguir ver o problema no seu editor de código, apenas quando você executar o código e der errado. Isso pode dificultar um pouco o processo de desenvolvimento.


O que é Query Builder ?

De forma resumida: São lib's ou pacotes que executam comandos SQL através de métodos ou funções.

Query Builder são uma alternativa muito interessante, basicamente eles compõem um conjunto de funções escritas em uma linguagem x e que representam os comandos nativos do SQL. No geral o query builder estão um nível a cima na camada de abstração em comparação com o Raw SQL, mas afinal como isso me ajuda 🤔?

Olha esse exemplo:

const express = require('express');
const knexDB = require('./knex');

const app = express();

app.get('/', async (req, res) => {
    const knexReturn = await knexDB('Users')
        .select('id', 'name')
        .where('name', req.query.name)

    res.send(knexReturn);
}); 

app.listen(3000, () => console.log('Running on PORT 3000'));
Enter fullscreen mode Exit fullscreen mode

Agora os comandos nativos do SQL são escritos como funções!

Vantagens

Limpeza dos inputs (Xô SQL Injection).

Alt Text

Limpeza dos input's? Exato! Quando temos uma camada a mais de abstração os métodos e funções ficam responsáveis por realizar a limpeza do input's do usuário, então comandos como SELECT * FROM "Users" WHERE name='' OR name='Admin' AND '1'='1' não irão ser mais gerados ou executados.

Olhe o exemplo abaixo:

Alt Text

No exemplo acima fizemos a tentativa de um SQL Injection no end-point, mas como resultado, nada foi retornado, por quê🤔? Como eu comentei o query builder tem uma camada a mais de abstração, isso permite que as funções limpem os input's feitos pelos usuários o que resulta no retorno vazio da chamada!

Facilidade na escrita.

No momento que vamos escrever nossas queries algumas vezes erramos os comandos, com o query builder isso fica um pouco mais fácil, veja o exemplo:

Alt Text
Agora nosso editor de código consegue entender exatamente o que queremos fazer 🎉 .

Desvantagens

Pouca abstração (Requer boa compreensão do SQL).

Talvez esse ponto seja um pouco controverso, mas irei explicar, quando temos pouca abstração dos bancos SQL isso requer uma compreensão mais apurada de como utilizar o SQL, em contraste, em abstrações maiores o uso do SQL pode ficar mais ofuscado.

De forma mais objetiva, pouca ou muita abstração vai depender do cenário da aplicação!

Suporte Nativo.

Sabe aquele momento que você escolhe o SGBD especifico só por causa de uma funcionalidade ou syntax, então, isso pode acabar sendo um problema com o Query Builder, claro que depende muito do query builder alguns podem ter os métodos e funções que você deseja utilizar, mas caso não tenha, você tera que fazer o uso do Raw mode.

O uso do Raw Mode nos faz pular a cerca


O que é ORM ?

De forma resumida: ORM's são pedaços de códigos que utilizam a Orientação a Objeto para representar o seu banco de dados.

Se formos comparar o ORM com todos os métodos citados, o ORM esta no topo da pirâmide no quesito abstração.

Alt Text

Pense que ORM fosse um carro do futuro (cheio de abstração), onde você nem precise saber como dirigir um carro para se deslocar.

Os ORM's no geral permitem você fazer as consultas no banco de dado sem que tenha um conhecimento concreto de SQL. Interessante não? Olhe o exemplo:

const express = require('express');
const UsersModel = require('./sequelize');

const app = express();

app.get('/', async (req, res) => {
    const result = await UsersModel.findAll({
        where: {
            name: req.query.name
        }
    });

    res.send(result);
}); 

app.listen(3000, () => console.log('Running on PORT 3000'));
Enter fullscreen mode Exit fullscreen mode
const { Sequelize, DataTypes } = require('sequelize');

const sequelize = new Sequelize('postgres://postgres:postgres@127.0.0.1:5432/NodeRawQuery');

const UsersModel = sequelize.define('Users', {
    id: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
    },
    name: DataTypes.STRING,
    age: DataTypes.INTEGER,
    password: DataTypes.STRING,
}, { timestamps: false });

module.exports = UsersModel;
Enter fullscreen mode Exit fullscreen mode

Se olharmos para a syntax o código fica mais elegante e descritivo, o que e ótimo!

Vantagens

Código mais descritivo.

Alt Text

O uso de ORM's permite que a escrita seja mais clara e descritiva, isso ajuda o desenvolvedor em focar no necessário (business logic).

Versionamento de bancos.

ORM's permitem você versionar seu banco, alguns query builders também, mas e bem relativo a stack em questão.

Desvantagens

Performance.

ORM's são os menos performáticos das soluções que foram citadas, o motivo para isso é por conta da conversão de código OOP para SQL Nativo, esse processo gera um custo para a performance.

Abstração.

ORM's são incríveis e permitem você ter uma produtividade muito boa, mas é muito importante que ao fazer o uso de ORM's o seu conhecimento em SQL seja solido, eventuais problemas podem acontecer e a abstração pode dificultar o processo de debug.


Conclusão

De forma resumida: ORM's e Query Builder's se mostram ótimas soluções, Raw SQL continua sendo uma solução porem precisa de uma tratativa a mais.

Irei sintetizar de forma objetiva os pontos citados no texto em uma tabela abaixo:

Comparativo

Gerenciamento Abstração Complexidade
Raw SQL Alto / Baixo
Query Builder Baixo Baixo Baixo
ORM's Baixo Alto Alto

De maneira geral, acho o conhecimento solido em SQL muito importante independente da solução, conhecer bem o SQL e fundamental no dia a dia de um desenvolvedor. Espero que tenham gostado! Até a próxima !!

Alt Text

Discussion (0)