question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

queryRaw template not working with Jest

See original GitHub issue

Bug description

I’m running the following SQL query with queryRaw:

const results = await prisma.$queryRaw`
        select
          posts.*,
          ${
            requestingUserId
              ? Prisma.sql`max(case when l.profile_id = ${requestingUserId} then 1 else 0 end) as is_liked_by_user,`
              : Prisma.empty
          }
          submitter.username
        from posts
        inner join user_profiles as submitter
          on posts.profile_id = submitter.id
        left join post_likes as l
          on posts.id = l.post_id
        where posts.show_id = ${showId}
        group by posts.id, posts.parent_post_id, submitter.username;
      `;

This works correctly with requestingUserId == undefined when running in a normal node.js environment, but when I run the same query in the same code via Jest I get an error:

Invalid `prisma.queryRaw()` invocation:
  Raw query failed. Code: `42601`. Message: `db error: ERROR: syntax error at or near "("`

I added some debug output to see the SQL and I notice it is trying to create a prepared statement in the select clause with what looks like the serialized JSON of the Prisma.empty object itself when I run in Jest (but it is correctly just inserting empty when running in the node server).

Node.js SQL

sql:
        select
          posts.*,

          sum(case when l.post_id is null then 0 else 1 end) as total_likes,
          submitter.username
        from posts
        inner join user_profiles as submitter
          on posts.profile_id = submitter.id
        left join post_likes as l
          on posts.id = l.post_id
        where posts.show_id = $1
        group by posts.id, posts.parent_post_id, submitter.username;
params: [550]

Jest SQL

sql:
            select
              posts.*,
              $1
              sum(case when l.post_id is null then 0 else 1 end) as total_likes,
              submitter.username
            from posts
            inner join user_profiles as submitter
              on posts.profile_id = submitter.id
            left join post_likes as l
              on posts.id = l.post_id
            where posts.show_id = $2
            group by posts.id, posts.parent_post_id, submitter.username;
params: [{"values":[],"strings":[""],"text":"","sql":""},550]

There’s not much difference between my jest setup and my node.js server. I’m using supertest when running Jest to hit the API, so I was thinking maybe it’s serializing+deserializing the Prisma.empty object to/from JSON and then failing some kind of instanceof check? But, I don’t pass the query object between Jest/Express or anything like that - the code that creates the query and executes it is colocated in just the server (as you can see from my snippet above)…

How to reproduce

  1. Write a queryRaw statement that conditionally inserts Prisma.empty into the query
  2. Execute this statement in a Jest test
  3. See odd prepared statement attempting to pass a serialized version of the Prisma.empty object as a parameter to the query

Expected behavior

Similar to how it works when running directly via node, the Prisma.empty portion should be omitted from the query

Prisma information

const results = await prisma.$queryRaw`
        select
          posts.*,
          ${
            requestingUserId
              ? Prisma.sql`max(case when l.profile_id = ${requestingUserId} then 1 else 0 end) as is_liked_by_user,`
              : Prisma.empty
          }
          submitter.username
        from posts
        inner join user_profiles as submitter
          on posts.profile_id = submitter.id
        left join post_likes as l
          on posts.id = l.post_id
        where posts.show_id = ${showId}
        group by posts.id, posts.parent_post_id, submitter.username;
      `;

Environment & setup

  • OS: macOS 12.1
  • Database: PostgreSQL
  • Node.js version: 16.13.0

Prisma Version

prisma                  : 3.8.1
@prisma/client          : 3.8.1
Current platform        : darwin-arm64
Query Engine (Node-API) : libquery-engine 34df67547cf5598f5a6cd3eb45f14ee70c3fb86f (at node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Migration Engine        : migration-engine-cli 34df67547cf5598f5a6cd3eb45f14ee70c3fb86f (at node_modules/@prisma/engines/migration-engine-darwin-arm64)
Introspection Engine    : introspection-core 34df67547cf5598f5a6cd3eb45f14ee70c3fb86f (at node_modules/@prisma/engines/introspection-engine-darwin-arm64)
Format Binary           : prisma-fmt 34df67547cf5598f5a6cd3eb45f14ee70c3fb86f (at node_modules/@prisma/engines/prisma-fmt-darwin-arm64)
Default Engines Hash    : 34df67547cf5598f5a6cd3eb45f14ee70c3fb86f
Studio                  : 0.452.0

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
SevInfcommented, Sep 8, 2022

I was able to reproduce it using the repo, provided by @idolize. I think you also correctly pointed out that the issues with this is a combination of instanceof check and jest sandbox. Now, step by step reproduction of what happens.

In your jest setup, you have a custom jest environment, which exposes prisma as a global. Jest loads environment file outside of its module sandbox, so any import '@prisma/client' resolves to a raw unmodified prisma module. Let’s call this instance of module “environment prisma”

Test files and all their imports do pass through sandbox. In your case, that’s server.ts, which imports Prisma.empty from @prisma/client. In that case, this is a different instance of the module - let’s call it “sandbox prisma” and Prisma.empty, imported from it “sanbox empty”.

In order to start your server, you need to pass it prisma instance. In your test this is environment prisma. To distingush between raw parameter and Prisma.Empty value, at some point a do a check, parameter instanceof EnvironmentPrisma.empty. However, it receives and instance of “sanbox empty” instead and the check fails.

Hope my explanation makes sense. Thank you for the great reproduction, @idolize.

While we are working on a fix, the workaround is to move new PrismaClient() creation into test file itself.

Ultimately, this is not jest-specific issue, even though it is probably most common setup where it could be observed. Any kind of cross-module Prisma.empty usage will fail and we should probably move away from instanceof checks in this case. That specific instanceof lives in sql-template-tag module.

1reaction
idolizecommented, Jun 10, 2022

@pantharshit00 Here is a repo I made with some simple instructions to reproduce the issue https://github.com/idolize/prisma-issue-11454

Read more comments on GitHub >

github_iconTop Results From Across the Web

Prisma queryRaw throws error when using template string ...
Hi, @chenliu9. Unfortunately, that's not a valid “Tagged template” replacement - they work when replacing items like parameters in where clauses ...
Read more >
Pulse · prisma/prisma · GitHub
Sometimes conversations happen on old items that aren't yet closed. Here is a list of all the Issues and Pull Requests with unresolved...
Read more >
Raw database access (Reference) - Prisma
For example, the following two queries would not work: const myTable = 'user' ... $queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.
Read more >
How to output raw SQL with filled parameters in TypeORM?
This almost worked out-of-the-box for me for TypeORM PSQL printing but had some issues where ? should have been $ and PSQL takes...
Read more >
Prisma 2.30.0 Release - GitClear
chore(deps): update dependency @types/jest to v27 ... If you have any comments or run into any problems we're available in this in this...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found