Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with dynamically building condition clause #813

Open
lz000 opened this issue Feb 21, 2024 · 8 comments
Open

Issue with dynamically building condition clause #813

lz000 opened this issue Feb 21, 2024 · 8 comments

Comments

@lz000
Copy link

lz000 commented Feb 21, 2024

I try to build a dynamic query with dynamic filters within a transaction but does not work. It returns 0 results.

Here is my code

let dynamicFilters = [
        transactionSql`id=${id}`,
        transactionSql`name=${name}`,
    ];


await transactionSql`
SELECT * FROM table WHERE ${ dynamicFilters.join(' AND ') }
`

I also tried below but does not work either

await transactionSql`
SELECT * FROM table WHERE ${ transactionSql`${ dynamicFilters.join(' AND ') }` }
`

If I replace the expression with the actual sql string it will work

await transactionSql`
SELECT * FROM table WHERE id=${id} AND name=${name} }
`

Any idea why?

@raprocks
Copy link

try debugging the query that the client creates, maybe might be helpful to understand if your conditions are correct.

  debug: (
    conn: number,
    query: string,
    params: unknown[],
    paramTypes: unknown[],
  ) => {
    logger.debug(`
    SQL::
      Executing query: "${query.trim()}"
      Params: ${JSON.stringify(params)}
      Param Types: ${JSON.stringify(paramTypes)}
      Connection: ${conn}
    `);
  },

put this in the postgres initialization options

@lz000
Copy link
Author

lz000 commented Feb 23, 2024

Here is my test results

let dynamicFilters = [
        transactionSql`id=${id}`,
        transactionSql`name=${name}`,
    ];


await transactionSql`
SELECT * FROM table WHERE ${ dynamicFilters.join(' AND ') }
`

The generated sql is SELECT * FROM table WHERE $1 and the param is [object Promise]

let dynamicFilters = [
        `id=${id}`,
        `name=${name}`,
    ];


await transactionSql`
SELECT * FROM table WHERE ${ transactionSql`${ dynamicFilters.join(' AND ') }` }
`

The generated sql is SELECT * FROM table WHERE $1 and the param is id=x AND name=x

let dynamicFilters = [
        transactionSql`id=${id}`,
        transactionSql`name=${name}`,
    ];


await transactionSql`
SELECT * FROM table WHERE ${ transactionSql`${ dynamicFilters.join(' AND ') }` }
`

The generated sql is SELECT * FROM table WHERE $1 and the param is ["[object Promise]"

try debugging the query that the client creates, maybe might be helpful to understand if your conditions are correct.

  debug: (
    conn: number,
    query: string,
    params: unknown[],
    paramTypes: unknown[],
  ) => {
    logger.debug(`
    SQL::
      Executing query: "${query.trim()}"
      Params: ${JSON.stringify(params)}
      Param Types: ${JSON.stringify(paramTypes)}
      Connection: ${conn}
    `);
  },

put this in the postgres initialization options

@raprocks
Copy link

the filter fragments are being generated as promises instead of SQL query fragments. maybe await before the fragments can help?

@lz000
Copy link
Author

lz000 commented Feb 23, 2024

the filter fragments are being generated as promises instead of SQL query fragments. maybe await before the fragments can help?

let dynamicFilters = [
        await transactionSql`id=${id}`,
        await transactionSql`name=${name}`,
    ];


await transactionSql`
SELECT * FROM table WHERE ${ dynamicFilters.join(' AND ') }
`

I tried that too, but got error invalid sql id=$1. Seems like it try to run each snippet

@henryzhang03
Copy link

bumping this, getting exactly the [object Promise] issue.

@henrywalters
Copy link

Bumping as well - pretty big deal breaker sadly :(

@Marviel
Copy link

Marviel commented May 9, 2024

Currently this requires you to use sql.unsafe to get around it, which is ugly and ... unsafe

const filters = [
    'foo IN ('nice')',
    'foo IN ('cool')
]

await sql`
SELECT foo FROM bar
${sql.unsafe(WHERE ${filters.join (' AND ')})}
`

@porsager I'm not an expert in either lib, but it seems the library-level fix for this would be a sql-safe .join, similar to what slonik has ?

What do you think?

@granthusbands
Copy link

So the problem you've got is that Array.prototype.join returns a string, and sql is not just strings. You need to use a join that correctly handles sql and parameters. You need each part to be an sql fragment, rather than a string. Look at the code in issue #807 if you're unsure.

(Note: Do not use unsafe or await for this; they both will have unexpected outcomes.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants