node.js & postgres

Como usar o node-postgres com query parametrizada

  • ligeiro Deividy Metheler Zachetti
  • 2018-02-12
blog-detail-hero

Digamos que você não tem um orm, ou simplesmente não quer usar um e decidiu usar o mais próximo possível do nativo. Nesse caso, o mínimo que podemos fazer é usar queries parametrizadas.

Queries parametrizadas (ou consultas parametrizadas, ou parameterized queries, ou ainda prepared statement) são basicamente consultas que escrevemos para o banco de dados com certos códigos para o módulo de acesso ao db pré compilar e nos proteger de algum código malicioso, ou algum tipo de SQL Injection.
Pense em parameterized queries como simplesmente variáveis que você passa para o seu componente de acesso ao banco de dados e ele garante o tipo e protege contra algum escape maldoso.


Com o node-postgres, temos duas formas de fazer isso:

 - 1) Usando apenas COLUMN = $N (onde N é a posição desse argumento em .query(STMT, args1, arg2...)).
 - 2) Passando o COLUMN = $N::TYPE (onde type pode ser text, int, datetime, etc.)


Aqui vamos desenvolver uma classe que irá cuidar de gerar a segunda forma de query pra gente, será algo bem simples e o problema que ela vai resolver é o de termos que lembrar sempre a posição do parâmetro e seu tipo, facilitando nossa escrita de statements.

Sem mais delongas, eis a nossa criança:

class DbArgs {
    constructor () {
    this._args = [ ];
    }

    add (value, type) {
    const argIndex = this._args.length + 1;
    const fullType = `$${argIndex}::${type}`;

    this._args.push({ argIndex, type, value, fullType });
    return fullType;
    }

    toArray () {
    // values only!
    return this._args.map((arg) => arg.value);
    }
}

Essa pequena classe simplesmente guarda nossos parâmetros em um array e retorna o text desejado, pronto para usarmos em nosso statemet, de forma que podemos escrever nosso código assim:

const args = new DbArgs();
    const stmt = `
    SELECT
    text
    FROM
    blog_post
    WHERE
    name = ${args.add('%parameterized-query%', 'text')} AND
    int_test = ${args.add(1, 'int')} AND
    date = ${args.add(new Date().getTime(), 'timestamp')};
    `;
    const res = client.query(stmt, args.toArray());

Esse código gera o seguinte statement:

SELECT
    text
    FROM
    blog_post
    WHERE
    name = $1::text AND
    int_test = $2::int AND
    date = $3::timestamp;

E o args.toArray(), retorna:

[ '%parameterized-query%', 1, 1518470278513 ]

Bem mais simples que ter que ficar cuidando de ordem e tipo de argumentos, né? :)