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

Using citext fields with neon database driver causes conversion error #21807

Closed
mmachatschek opened this issue Nov 6, 2023 · 1 comment · Fixed by #22239
Closed

Using citext fields with neon database driver causes conversion error #21807

mmachatschek opened this issue Nov 6, 2023 · 1 comment · Fixed by #22239
Assignees
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug. team/client Issue for team Client. topic: @db.Citext Native type `Citext` topic: driverAdapters topic: preview 👁 topic: previewFeatures Issue touches on an preview feature flag
Milestone

Comments

@mmachatschek
Copy link

Bug description

Using the postgres extension Citext on a field causes the error:

Error converting field "slug" of expected non-nullable type "String", found incompatible value of "someslug".

How to reproduce

  1. Use citext postgres extension on any field in a model
  2. Fetch data from that model
  3. See error:
Error converting field "slug" of expected non-nullable type "String", found incompatible value of "someslug".

Some debug logs:

  prisma:client  Prisma Client call: +670ms
  prisma:client  prisma.someModel.findMany({
  where: {
    slug: {
      equals: "someslug"
    }
  },
  select: {
    id: true,
    slug: true
  }
}) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  {
  "modelName": "SomeModel",
  "action": "findMany",
  "query": {
    "arguments": {
      "where": {
        "slug": {
          "equals": "someslug"
        }
      }
    },
    "selection": {
      "id": true,
      "slug": true
    }
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: false +669ms
  prisma:client:engines:resolveEnginePath  enginePath /Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node +0ms
  prisma:client:libraryEngine  Using driver adapter: %O {
  errorRegistry: oc { registeredErrors: [] },
  queryRaw: [AsyncFunction (anonymous)],
  executeRaw: [AsyncFunction (anonymous)],
  flavour: 'postgres',
  startTransaction: [AsyncFunction: startTransaction],
  close: [AsyncFunction (anonymous)]
} +8ms
  prisma:client:libraryEngine  library starting +17ms
  prisma:client:libraryEngine  library started +2ms
  prisma:driver-adapter:neon [js::query_raw] {
  prisma:driver-adapter:neon   sql: 'SELECT "public"."SomeModel"."id", "public"."SomeModel"."slug" FROM "public"."SomeModel" WHERE "public"."SomeModel"."slug" = $1 OFFSET $2',
  prisma:driver-adapter:neon   args: [ 'someslug', 0 ]
  prisma:driver-adapter:neon } +0ms
  prisma:client:request_handler  PrismaClientKnownRequestError: Error converting field "slug" of expected non-nullable type "String", found incompatible value of "someslug".
    at Zt (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:36:253)
    at mr.buildQueryError (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:115:1216)
    at mr.request (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:114:4091)
    at async Object.singleLoader (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:123:5333)
    at async Cn.request (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:123:5825)
    at async l (/Users/markus/prisma/node_modules/.pnpm/@prisma+client@5.5.2_prisma@5.5.2/node_modules/@prisma/client/runtime/library.js:128:9968)
    at async /Users/markus/prisma/script.ts:13:5 {
  code: 'P2032',
  clientVersion: '5.5.2',
  meta: { field: 'slug', expected_type: 'String', found: 'someslug' }
} +0ms

Expected behavior

Prisma should correctly convert Citext fields to strings

Prisma information

datasource postgresql {
  url               = env("DATABASE_URL")
  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
  provider          = "postgresql"
  directUrl         = env("DIRECT_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["driverAdapters"]
}

model SomeModel {
  id                                     String                 @id @default(cuid())
  slug                                   String                 @unique @default("") @postgresql.Citext
}
await prisma.someModel.findMany({
      where: {
        slug: {
          equals: 'someslug',
        },
      },
      select: {
        id: true,
        slug: true,
      },
    })
  );

Environment & setup

  • OS: macOS
  • Database: PostgreSQL v14
  • Node.js version: v18

Prisma Version

prisma                  : 5.5.2
@prisma/client          : 5.5.2
Current platform        : darwin-arm64
Query Engine (Node-API) : libquery-engine aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a (at ../../node_modules/.pnpm/@prisma+engines@5.5.2/node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Schema Engine           : schema-engine-cli aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a (at ../../node_modules/.pnpm/@prisma+engines@5.5.2/node_modules/@prisma/engines/schema-engine-darwin-arm64)
Schema Wasm             : @prisma/prisma-schema-wasm 5.5.1-1.aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a
Default Engines Hash    : aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a
Studio                  : 0.494.0
Preview Features        : driverAdapters
@mmachatschek mmachatschek added the kind/bug A reported bug. label Nov 6, 2023
@janpio janpio added topic: @db.Citext Native type `Citext` topic: driverAdapters bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. team/client Issue for team Client. labels Nov 6, 2023
@Jolg42 Jolg42 self-assigned this Nov 7, 2023
@Jolg42 Jolg42 added 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 Nov 7, 2023
@Jolg42
Copy link
Member

Jolg42 commented Nov 7, 2023

I could reproduce in 5.5.2 (and also in 5.6.0-dev.73)

I had to do a create operation to reproduce this.

Note: I also tried without driverAdapters and it worked as expected.

PrismaClientKnownRequestError: 
Invalid `prisma.someModel.create()` invocation in
/Users/j42/Repros/21807/main.ts:17:41

  14 // const data = await prisma.user.findMany()
  15 // console.log(data)
  16 
→ 17 const create = await prisma.someModel.create(
Error converting field "slug" of expected non-nullable type "String", found incompatible value of "someslug".
    at Cn.handleRequestError (/Users/j42/Repros/21807/node_modules/@prisma/client/runtime/library.js:123:6817)
    at Cn.handleAndLogRequestError (/Users/j42/Repros/21807/node_modules/@prisma/client/runtime/library.js:123:6206)
    at Cn.request (/Users/j42/Repros/21807/node_modules/@prisma/client/runtime/library.js:123:5926)
    at async l (/Users/j42/Repros/21807/node_modules/@prisma/client/runtime/library.js:128:9968)
    at async main (/Users/j42/Repros/21807/main.ts:17:18) {
  code: 'P2032',
  clientVersion: '5.5.2',
  meta: { field: 'slug', expected_type: 'String', found: 'someslug' }
}

using

import { PrismaClient } from "@prisma/client";
import { Pool, neonConfig } from "@neondatabase/serverless";
import { PrismaNeon } from "@prisma/adapter-neon";
import ws from "ws";

neonConfig.webSocketConstructor = ws;
const connectionString = `postgres://user:password@ep-something-pooler.eu-central-1.aws.neon.tech/mydb`;

async function main() {
  const pool = new Pool({ connectionString });
  const adapter = new PrismaNeon(pool);
  const prisma = new PrismaClient({ adapter });

  await prisma.someModel.deleteMany({
    where: {
      slug: {
        equals: "someslug",
      },
    },
  });

  // Errors here
  // Error converting field "slug" of expected non-nullable type "String", found incompatible value of "someslug".
  const create = await prisma.someModel.create({
    data: {
      slug: "someslug",
    },
  });
  console.debug({ create });

  const findMany = await prisma.someModel.findMany({
    where: {
      slug: {
        equals: "someslug",
      },
    },
    select: {
      id: true,
      slug: true,
    },
  });
  console.debug({ findMany });

  prisma.$disconnect();
}

main();

@Jolg42 Jolg42 added the topic: previewFeatures Issue touches on an preview feature flag label Nov 7, 2023
@Jolg42 Jolg42 removed their assignment Nov 8, 2023
@aqrln aqrln self-assigned this Nov 8, 2023
@janpio janpio added this to the 5.7.0 milestone Nov 13, 2023
@Jolg42 Jolg42 modified the milestones: 5.7.0, 5.8.0 Dec 8, 2023
aqrln added a commit that referenced this issue Dec 8, 2023
 Treat all custom Postgres types as text in the result set.

This is an alternative to #21918.

Thanks to driver adapters using Postgres text protocol, unlike our native driver that uses the binary protocol, we can get away with treating all unknown extension types as text if we want to expose them to users as such — we (or the driver) don't need to know how to decode them and convert to strings if they are already strings in the first place.

However, we cannot distinguish between known types added by extensions and enums without querying the catalog for type names. This may look like a problem at first, but in reality we can get away with treating enums as text in result set too, the response IR layer in the query engine uses the query schema to know it's an enum, not the type hint that comes from `quaint::Value`/`PrismaValue`. If the output type in the query schema says it's an enum, it will treat `PrismaValue::String` and `PrismaValue::Enum` equally: https://github.com/prisma/prisma-engines/blob/12d71c4263690f3990d590fbff611b2a24ef2dbc/query-engine/core/src/response_ir/internal.rs#L813. So mapping Postgres enums to `quaint::ValueType::Text` is fine, and is already supported by QE.

Engines test suite passing: prisma/prisma-engines#4531

Fixes: #21807
Closes: #21918

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
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: @db.Citext Native type `Citext` topic: driverAdapters topic: preview 👁 topic: previewFeatures Issue touches on an preview feature flag
Projects
None yet
5 participants