graphql-nexus / nexus-plugin-prisma

Deprecated
MIT License
829 stars 118 forks source link

Allow GraphQL args to pass through to Prisma client #857

Open iherger opened 4 years ago

iherger commented 4 years ago

Description

Updating to nexus@0.24.0 and nexus-plugin-prisma@0.10.0 gives the following errors:

  Types of property 'id' are incompatible.
    Type 'string | null | undefined' is not assignable to type 'string | undefined'.
      Type 'null' is not assignable to type 'string | undefined'.

for a resolver that used to work before and that starts as follows

Screenshot 2020-06-17 at 08 25 33

Nexus Report

{
  "node": "v12.11.0",
  "os": {
    "platform": "darwin",
    "release": "19.5.0"
  },
  "nexus": "^0.24.0",
  "plugins": [
    "nexus-plugin-prisma",
    "nexus-plugin-shield"
  ],
  "otherDependencies": {
    "@prisma/client": "2.0.1",
    "aws-sdk": "^2.696.0",
    "axios": "^0.19.2",
    "bcrypt": "^5.0.0",
    "cors": "^2.8.5",
    "ejs": "^3.1.3",
    "jsonwebtoken": "^8.5.1",
    "moment": "2.26.0",
    "moment-timezone": "^0.5.31",
    "nodemailer": "^6.4.8",
    "stripe": "^8.63.0",
    "ua-parser-js": "^0.7.21",
    "uuid": "^8.1.0"
  },
  "devDependencies": {
    "@prisma/cli": "2.0.1",
    "@types/bcrypt": "^3.0.0",
    "@types/cors": "^2.8.6",
    "@types/ejs": "^3.0.4",
    "@types/faker": "^4.1.12",
    "@types/jsonwebtoken": "^8.5.0",
    "@types/nodemailer": "^6.4.0",
    "@types/prettier": "^2.0.1",
    "@types/ua-parser-js": "^0.7.33",
    "@types/uuid": "^8.0.0",
    "@typescript-eslint/eslint-plugin": "^3.2.0",
    "@typescript-eslint/parser": "^3.2.0",
    "eslint": "^7.2.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.3",
    "faker": "^4.1.0",
    "husky": "^4.2.5",
    "prettier": "^2.0.5",
    "typescript": "3.9.5"
  },
  "hasAppModule": true,
  "packageManager": "yarn",
  "errorsWhileGatheringReport": {
    "gettingLayout": null,
    "gettingPluginManifests": null
  }
}
Weakky commented 4 years ago

This is unfortunately not a bug. Prisma Client has changed its types so that it doesn't always accept null because it has semantic meaning for the database.

However, GraphQL.js always accepts null | undefined for nullable field args. This mean there's now a discrepancy between what GraphQL, at the API layer accepts, and what Prisma Client, at the database layer accepts.

TLDR: Until we come up with some sort of helper to make the conversion between the GraphQL args and what the Prisma Client accepts, you'll need to destructure the args and pass the fields one by one so that you can convert the nulls to undefineds. eg:

resolve(root, args) {
  return ctx.db.user.create({
    data: {
      name: args.data.name ?? undefined
    }
  })
}
iherger commented 4 years ago

Thanks for the explanation. That's unfortunate, indeed.

I found it quite comfortable to use the nexus-generated input types for some larger input arguments, and having to destructure args makes it considerable less comfortable.

Weakky commented 4 years ago

We're indeed aware. I'll leave your issue opened until we find a solution.

Beware though that this is not purely a typing issue. If you or a consumer of your API ever passes a null on a field that shouldn't be null in the Prisma Client, it will break.

For the record, we've implemented a helper for the generated nexus-prisma resolvers. The reason we haven't exposed that helper is for two reasons:

  1. To perform the transformation, we need access to DMMF, an internal Prisma Schema AST to safely convert the nulls to undefined only on the fields that aren't nullable at the DB layer. To find that information in the DMMF, we need the typename + field name in which you're trying to do the conversion.

  2. To make that helper type-safe, we probably need to do additional typegen so that we trim out the nulls only on the right fields, according to the DMMF again.

Because of 1. and 2., we can't just expose a pure function that does the transformation. It needs additional context and we need to figure out how to prevent users from having to pass that context (the DMMF, type name, field name etc). Without that, the signature would more or less look like so 👇, which we find inconvenient and error-prone as well.

function transformNullsToUndefined(graphqlArgs: GraphQLArgs, typeName: string, fieldName: string, dmmf: DMMF): SomeTypeSafeResult
oceandrama commented 4 years ago

Really annoying problem. The only workaround - a lot of // @ts-expect-error. Any updates?

homerjam commented 3 years ago

Is there a workaround for this regression?

(apart from // @ts-expect-error 😄 )

scriptcoded commented 3 years ago

For the record, we've implemented a helper for the generated nexus-prisma resolvers. The reason we haven't exposed that helper is for two reasons:

@Weakky Is there any way to get hold of these DMMF args outside of Prisma, or will we just have to wait for a solution?

MikaStark commented 3 years ago

A little dirty workaround for your tsconfig :

"strict": true,
"strictNullChecks": false,