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

findUnique used with Promise.all returns null #18096

Closed
thomasjiangcy opened this issue Feb 25, 2023 · 10 comments · Fixed by prisma/prisma-engines#3818
Closed

findUnique used with Promise.all returns null #18096

thomasjiangcy opened this issue Feb 25, 2023 · 10 comments · Fixed by prisma/prisma-engines#3818
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug. team/client Issue for team Client. topic: BigInt scalar type `BigInt` topic: null topic: Promise.all
Milestone

Comments

@thomasjiangcy
Copy link

Bug description

There is an unexpected behaviour with .findUnique() and Promise.all() similar to #4438.

When used together, it returns an array of null:

// Assuming these IDs exist in the DB
await Promise.all(
  [1n, 2n, 3n].map(async (id) => await prisma.user.findUnique({
    where: {
      id
    }
  })
);

// Returns [null, null, null]

However, using .findUniqueOrThrow() with Promise.all() seems to work as expected.


How to reproduce

Here's a minimally reproducible repository - https://github.com/thomasjiangcy/prisma-promise-all-find-unique-bug

  1. Clone the repository
  2. npm install
  3. docker compose up -d (if you have docker compose installed, if not you can run postgres another way)
  4. npx prisma migrate dev
  5. npx ts-node index.ts

Output of DEBUG='*' npx ts-node index.ts

  prisma:tryLoadEnv  Environment variables loaded from /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/.env +0ms
  prisma:tryLoadEnv  Environment variables loaded from /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/.env +2ms
  prisma:client  dirname /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/node_modules/.prisma/client +0ms
  prisma:client  relativePath ../../../prisma +0ms
  prisma:client  cwd /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/prisma +0ms
  prisma:client  clientVersion 4.10.1 +0ms
  prisma:client  clientEngineType library +0ms
  prisma:client:libraryEngine  internalSetup +0ms
  prisma:client:libraryEngine:loader  Searching for Query Engine Library in /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/node_modules/.prisma/client +0ms
  prisma:client:libraryEngine:loader  loadEngine using /Users/thomasjiang/Projects/prisma-promise-all-find-unique-bug/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node +0ms
  prisma:client:libraryEngine  library starting +13ms
  prisma:client:libraryEngine  library started +44ms
  prisma:client  Prisma Client call: +68ms
  prisma:client  prisma.connection.create({
  data: {
    name: 'Connection 1',
    user: {
      create: {
        name: 'User 1'
      }
    }
  }
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createOneConnection(data: {
    name: "Connection 1"
    user: {
      create: {
        name: "User 1"
      }
    }
  }) {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +12ms
  prisma:client  Prisma Client call: +31ms
  prisma:client  prisma.connection.create({
  data: {
    name: 'Connection 2',
    user: {
      create: {
        name: 'User 2'
      }
    }
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createOneConnection(data: {
    name: "Connection 2"
    user: {
      create: {
        name: "User 2"
      }
    }
  }) {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +30ms
  prisma:client  Prisma Client call: +4ms
  prisma:client  prisma.connection.create({
  data: {
    name: 'Connection 3',
    user: {
      create: {
        name: 'User 3'
      }
    }
  }
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createOneConnection(data: {
    name: "Connection 3"
    user: {
      create: {
        name: "User 3"
      }
    }
  }) {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +5ms
  prisma:client  Prisma Client call: +3ms
  prisma:client  prisma.connection.create({
  data: {
    name: 'Connection 4',
    user: {
      create: {
        name: 'User 4'
      }
    }
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createOneConnection(data: {
    name: "Connection 4"
    user: {
      create: {
        name: "User 4"
      }
    }
  }) {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +4ms
  prisma:client  Prisma Client call: +4ms
  prisma:client  prisma.connection.create({
  data: {
    name: 'Connection 5',
    user: {
      create: {
        name: 'User 5'
      }
    }
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createOneConnection(data: {
    name: "Connection 5"
    user: {
      create: {
        name: "User 5"
      }
    }
  }) {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +3ms
  prisma:client  Prisma Client call: +4ms
  prisma:client  prisma.connection.findMany(undefined) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findManyConnection {
    id
    name
    userId
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +4ms
  prisma:client  Prisma Client call: +3ms
  prisma:client  prisma.user.findUnique({
  where: {
    id: '1'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUser(where: {
    id: 1
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUnique({
  where: {
    id: '2'
  }
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUser(where: {
    id: 2
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUnique({
  where: {
    id: '3'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUser(where: {
    id: 3
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUnique({
  where: {
    id: '4'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUser(where: {
    id: 4
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUnique({
  where: {
    id: '5'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUser(where: {
    id: 5
  }) {
    id
    name
  }
}
 +0ms
  prisma:client:libraryEngine  requestBatch +4ms
[ null, null, null, null, null ]
  prisma:client  Prisma Client call: +5ms
  prisma:client  prisma.user.findUniqueOrThrow({
  where: {
    id: '1'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUserOrThrow(where: {
    id: 1
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUniqueOrThrow({
  where: {
    id: '2'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUserOrThrow(where: {
    id: 2
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUniqueOrThrow({
  where: {
    id: '3'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUserOrThrow(where: {
    id: 3
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUniqueOrThrow({
  where: {
    id: '4'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUserOrThrow(where: {
    id: 4
  }) {
    id
    name
  }
}
 +0ms
  prisma:client  Prisma Client call: +0ms
  prisma:client  prisma.user.findUniqueOrThrow({
  where: {
    id: '5'
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findUniqueUserOrThrow(where: {
    id: 5
  }) {
    id
    name
  }
}
 +0ms
  prisma:client:libraryEngine  requestBatch +6ms
[
  { id: 1n, name: 'User 1' },
  { id: 2n, name: 'User 2' },
  { id: 3n, name: 'User 3' },
  { id: 4n, name: 'User 4' },
  { id: 5n, name: 'User 5' }
]
  prisma:client:libraryEngine  library stopping +56ms
  prisma:client:libraryEngine  library stopped +0ms
  prisma:client:libraryEngine:exitHooks  exit event received: beforeExit +0ms
  prisma:client:libraryEngine:exitHooks  exit event received: exit +0ms

Expected behavior

Using .findUnique() with Promise.all() should return an array of unique objects.

Prisma information

generator client {
  provider        = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id    BigInt  @id @default(autoincrement())
  name  String  @db.VarChar(255)

  connections Connection[]
}

model Connection {
  id      BigInt  @id @default(autoincrement())
  name    String  @db.VarChar(255)
  userId  BigInt
  user    User    @relation(fields: [userId], references: [id], onDelete: NoAction, onUpdate: NoAction)
}
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  for (let i = 0; i < 5; i++) {
    await prisma.connection.create({
      data: {
        name: `Connection ${i + 1}`,
        user: {
          create: {
            name: `User ${i + 1}`
          }
        }
      }
    });
  }

  const allConnections = await prisma.connection.findMany();
  const allConnectionTeamMembers_promiseAllFindUnique = await Promise.all(allConnections.map(async connection => await prisma.user.findUnique({
    where: {
      id: connection.userId
    }
  })));
  console.log(allConnectionTeamMembers_promiseAllFindUnique);

  const allConnectionTeamMembers_promiseAllFindUniqueOrThrow = await Promise.all(allConnections.map(async connection => await prisma.user.findUniqueOrThrow(({
    where: {
      id: connection.userId
    }
  }))));
  console.log(allConnectionTeamMembers_promiseAllFindUniqueOrThrow);
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

Environment & setup

  • OS: macOS 13.2.1
  • Database: PostgreSQL 14.3
  • Node.js version: v19.6.1

Prisma Version

prisma                  : 4.10.1
@prisma/client          : 4.10.1
Current platform        : darwin-arm64
Query Engine (Node-API) : libquery-engine aead147aa326ccb985dcfed5b065b4fdabd44b19 (at node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Migration Engine        : migration-engine-cli aead147aa326ccb985dcfed5b065b4fdabd44b19 (at node_modules/@prisma/engines/migration-engine-darwin-arm64)
Format Wasm             : @prisma/prisma-fmt-wasm 4.10.1-1.80b351cc7c06d352abe81be19b8a89e9c6b7c110
Default Engines Hash    : aead147aa326ccb985dcfed5b065b4fdabd44b19
Studio                  : 0.481.0
@thomasjiangcy thomasjiangcy added the kind/bug A reported bug. label Feb 25, 2023
@reteps
Copy link

reteps commented Feb 25, 2023

Just lost my mind over this, thank you ❤️

@EduardoBautista
Copy link

EduardoBautista commented Feb 28, 2023

This is also an issue when trying to use findUnique to avoid N+1 calls in GraphQL field resolvers. So it might be related to batching?

@nic-rod
Copy link

nic-rod commented Feb 28, 2023

Also running into this - seems like a pretty significant issue. Seeing the issue on 4.7.1.

@janpio janpio added bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. team/client Issue for team Client. topic: null topic: Promise.all bug/2-confirmed Bug has been reproduced and confirmed. and removed bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. labels Mar 2, 2023
@janpio
Copy link
Member

janpio commented Mar 2, 2023

I can confirm this observation with the provided reproduction repository. Thanks for that @thomasjiangcy.

@aqrln
Copy link
Member

aqrln commented Mar 2, 2023

I can reproduce this when the type of id is BigInt but not when it is Int.

@Nickersoft
Copy link

Nickersoft commented Mar 11, 2023

Not sure if this is related, but after upgrade to 4.10.0+ I'm seeing null get returned randomly for standalone findUnique calls that previously worked fine. Sometimes the call returns a value, other times null. I output the raw SQL via Prisma logging, ran it in my database manager, and was able to get rows back. I'm currently stuck on 4.9.0 as a result.

Edit: Just saw @EduardoBautista's comment regarding batching, which I am using. Surprised this is being seeing on versions 4.9.0 and below, though.

@nik-lampe
Copy link

nik-lampe commented Mar 20, 2023

We're having the same issue since upgrading to 4.10.
With 4.9. it works fine, like @Nickersoft commented.

Is there a way to disable the batching?
Otherwise we'll just stick to 4.9 until this is resolved :)

@moishinetzer
Copy link

moishinetzer commented Aug 18, 2023

I'm seeing this issue on prisma version 5.1.1

Update: This is enum related

@janpio
Copy link
Member

janpio commented Aug 22, 2023

Can you open a new issue @moishinetzer, optimally with a reproduction so we can observe this ourselves? Thanks.

@moishinetzer
Copy link

Sorry for not updating: It seems to be resolved now. My dependencies weren't matching between prisma and @prisma/client thanks for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug. team/client Issue for team Client. topic: BigInt scalar type `BigInt` topic: null topic: Promise.all
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants