hasura / hasura/graphql-engine
server: mutation fails when we pass non-default value for ENUM where ENUM and table are defined in non-public schema
- Dominant language
- TypeScript
- Stars
- 32.1k
- Forks
- 3k
- PR merge metrics
- PR metrics pending
Description
### Version Information
Server Version: 2.36.1
### What is the current behaviour?
When ENUM defined as [native postgres ENUM type](https://hasura.io/docs/latest/schema/postgres/enums/#pg-native-enum) inside non-public schema and it's used by table which is also defined in non-public schema, then upon passing value to that ENUM type column in GQL mutation will yield an error suggesting you need to cast expression (which references the enum type from public schema instead of non-public schema where its defined).
### What is the expected behaviour?
Currently, from the error and the generated SQL it seems like its referring expression in public schema syntax rather than schema specific syntax. It should reference the scope from where its defined rather than template public reference. Apologies if my language here regarding SQL terminology confuses, but you will eventually know what I am describing in below steps to reproduce section.
### How to reproduce the issue?
Scenario : You define a [native postgres ENUM type](https://hasura.io/docs/latest/schema/postgres/enums/#pg-native-enum) inside a non-public schema and you use it in table which is also in non-public schema , i.e. both ENUM and table defined in non-public schema.
For Example,
I am defining ENUM `user_type` inside `user` schema
```sql
CREATE TYPE "user"."user_type" AS ENUM (
'ADMIN',
'BETA',
'USER'
);
```
In same schema, I define customer table which uses ENUM as one of its column types
```sql
CREATE TABLE "user"."customer" (
"id" varchar UNIQUE PRIMARY KEY NOT NULL,
"first_name" varchar NOT NULL,
"last_name" varchar NOT NULL,
"type" "user".user_type DEFAULT 'USER',
);
```
Note that I've reference `"user".user_type` as ENUM type and I've used default value "USER"
Assuming it's tracked as part of GraphQL API and now when I execute mutation with non-default value for `type` column in customer
```gql
mutation insertCustomer {
insert_user_customer_one(object: {first_name: "John", id: "example_user_1", last_name: "Doe", type: "BETA"}) {
first_name
id
last_name
type
}
}
```
It throws error as
```json
{
"errors": [
{
"message": "database query error",
"extensions": {
"path": "$.selectionSet.insert_user_customer_one.args.object",
"code": "unexpected",
"internal": {
"arguments": [],
"error": {
"description": null,
"exec_status": "FatalError",
"hint": "You will need to rewrite or cast the expression.",
"message": "column \"type\" is of type \"user\".user_type but expression is of type user_type",
"status_code": "42804"
},
"prepared": false,
"statement": "WITH \"_mra__user_customer\" AS (INSERT INTO \"user\".\"customer\" ( \"first_name\", \"id\", \"last_name\", \"type\" ) VALUES (('John')::varchar, ('example_user_5')::varchar, ('Doe')::varchar, ('BETA')::\"user_type\") RETURNING * , ('true')::boolean AS \"check__constraint\"), \"_aca__user_customer\" AS (SELECT \"id\" , \"first_name\" , \"last_name\" , \"type\" FROM \"_mra__user_customer\" ) SELECT (SELECT coalesce((json_agg(\"root\" )->0), 'null' ) AS \"root\" FROM (SELECT row_to_json((SELECT \"_e\" FROM (SELECT \"_root.base\".\"first_name\" AS \"first_name\", \"_root.base\".\"id\" AS \"id\", \"_root.base\".\"last_name\" AS \"last_name\", \"_root.base\".\"type\" AS \"type\" ) AS \"_e\" ) ) AS \"root\" FROM (SELECT * FROM \"_aca__user_customer\" WHERE ('true') ) AS \"_root.base\" ) AS \"_root\" ) , (SELECT coalesce(bool_and(\"check__constraint\" ), 'true' ) FROM \"_mra__user_customer\" ) /* field_name=insert_user_customer_one, parameterized_query_hash=5007afa20ed5bf506cfedfdf25b30605d9d3669e, operation_name=insertCustomer */"
}
}
}
]
}
```
If you directly execute SQL state for an insert , then it wouldn't throw error
```
INSERT INTO "user"."customer" (id,first_name,last_name,type) VALUES ('example_user_3','Mike','Stanley','BETA');
```
So it seems the generated SQL is the culprit here. I can see in full error message that it describes `('BETA')::\"user_type\"` where I think it should have `('BETA')::\"user"."user_type\"`
### Any possible solutions/workarounds you're aware of?
If you define ENUM in public schema but use it in table defined in non-public schema, then it will work flawlessly.
### Screenshots
### Keywords
generated sql ENUM
Contributor guide
Research direction
Start by reproducing the insert_user_customer_one mutation with a native PostgreSQL ENUM and table in the non-public "user" schema, then inspect the generated SQL shown in the report. The issue is done when the mutation casts the value using the schema-qualified ENUM type and succeeds for a non-default value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, postgres
- Domain
- api, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100