Reputation: 6778
I'm looking for a way to dynamically build a SQL query for an unknown number of API parameters that may come back. As a simple example, consider the following query:
router.get("/someEndpoint", authorizationFunction, async (req, res) => {
let sql = `
SELECT *
FROM some_table
WHERE username = $1
${req.query.since !== undefined ? "AND hire_date >= $2" : ""}
`
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
where pool
is defined as
const Pool = require("pg").Pool;
const pool = new Pool({<connection parameters>});
The problem I'm having is that if req.query.since
is not provided, then the SQL query only requires a single bound parameter ($1
). This is presented as an error that says bind message supplies 2 parameters, but prepared statement "" requires 1
. Since I don't know which parameters a user will provide until the time of the query, I'm under the impression that I need to provide all possible value, and let the query figure it out.
I've seen a lot of posts that point to pg-promise as a solution, but I'm wondering if that's necessary. Is there a way that I can solve this with my current setup? Perhaps I'm thinking about the problem incorrectly?
Thanks in advance!
Upvotes: 0
Views: 480
Reputation: 13029
Add a trivial expression text that contains $2
and evaluates to true
instead of ""
, for example
SELECT * FROM some_table WHERE username = $1 AND
${req.query.since !== undefined ? " hire_date >= $2": " (true or $2 = $2)"}
The planner will remove it anyway. Added true or
just in case $2
is null.
Still it would be cleaner like this
if (req.query.since !== undefined)
{
let sql = `SELECT * FROM some_table WHERE username = $1 AND hire_date >= $2`;
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
else
{
let sql = `SELECT * FROM some_table WHERE username = $1`;
const results = await pool.query(sql, [req.query.user]);
}
What about SQLi risk BTW?
Upvotes: 1