prisma: Use enum with reference table does not work until 5.4.0
Bug description
With the previous versions of prisma and @prisma/client we were able to use the enum inside our schema.prisma and point on our reference table that matches this enum. Since 5.4.0, which includes improvements around how prisma handle enums, we are not able to upgrade because the code now throw errors while using those enums in a where of a findMany or in the data of a create.
The documentation does not mention this was something supported, but it worked for us and we prefer working with table instead of an enum type on the database point of view, for the visibility that gives while debugging.
How to reproduce
-
Have a currency table with only one column called abbreviation and some values stored in this table
-
Create another table that referes the currency table, in our case billing_settings that has a currency column
-
In the
prisma.schemawe haveenum Currency { CAD USD [...] <-- all the currencies we are supporting are listed here @@map("currency") } model BillingSettings { [...] currency Currency @default(USD) } -
In the code just call prisma with
await getPrismaClient().billingSettings.findMany({ where: { currency: Currency.CAD } });or
await getPrismaClient().billingSettings.create({ data: { ...billingSettings, currency: Currency.CAD } }); -
The code will fail
findManyError occurred during query execution: ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(PostgresError { code: "42883", message: "operator does not exist: text = ecurrency", severity: "ERROR", detail: None, column: None, hint: Some("No operator matches the given name and argument types. You might need to add explicit type casts.") }), transient: false })createError occurred during query execution: ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(PostgresError { code: "22P02", message: "malformed record literal: \"CAD\"", severity: "ERROR", detail: Some("Missing left parenthesis."), column: None, hint: None }), transient: false })
Expected behavior
Both queries would work like they were on 5.3.0 and below
Prisma information
Already provided in the description
Environment & setup
- OS: macOS
- Database: PostgreSQL
- Node.js version: v18.16.0
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/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Schema Engine : schema-engine-cli aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a (at 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 : views
About this issue
- Original URL
- State: open
- Created 8 months ago
- Reactions: 6
- Comments: 15 (7 by maintainers)
@Jolg42 There you go, I’ve been able to reproduce it in this project: https://github.com/jimmyfortinx/prisma-issue-21693
@@represent-as-tableas described would be a good option for us. We are not using prisma’s generated migration SQL, so it seems like the issue about the column name won’t affect us. Am I wrong?@@represent-as-table(column: "abbreviation")sounds like a good option to provide the column name if I’m wrong on the previous part.On 5.3.0
On 5.5.2
The issue seems to be coming from the cast.
$2vsCAST($2::text AS "public"."currency")and$1vsCAST($1::text AS "public"."currency")We favour the use of a reference table for constraining values because:
Ok, I only now looked deeper at the reproduction and undertstood that the
currencyfield that is supposed to point to the enum, is replaced with aTEXTfield instead which has a reference to thecurrency.abbreviationfield (which contains all the enum values): https://github.com/jimmyfortinx/prisma-issue-21693/blob/4859f79ad6943340eb0b5f598d048fbe262cb90e/database/migrations/20231031133254_create-tables.js#L16 That gives similar guarantees like a real enum in that only existing values can be set, and updated are potentially also handled correctly.Going into speculative mode:
The correct way forward here would then be to add this as a proper feature to Prisma, that one can choose for
enumsto be represented via tables instead of enums. It would probably have to be an attribute toenumblocks (@@represent-as-table, hopefully a bit more elegant) and then we would need to update the generated migration SQL for enums accordingly.The name of the table we could just get from the
enum, but the column name (in your caseabbreviation) does not exist yet. Would you be ok with a generic name for that or is being able to call it a specific name relevant and important for you? (That would probably mean another option for the new attribute,@@represent-as-table(column: "abbreviation").@janpio would you be able to provide some guidance as to where this SQL generation is made in the code? Maybe we could help by contributing if this is not expected to be fixed anytime soon?
Thank you 🙏