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

Hasura 2.0: cannot insert NULL on nullable column (specifically for nested inserts) #7484

Closed
tokestermw opened this issue Aug 31, 2021 · 8 comments

Comments

@tokestermw
Copy link

Hi, say we have a table A

id: number, primary key, unique, default: nextval
related_id: integer, nullable

and table B

id: number, primary key, unique, default: nextval
related_text: string

w/ foreign keys

related_id -> B.id

and add a relationship called relationship

Now since related_id is nullable, we should be able to insert

mutation MyMutation {
  insert_A(objects: {relationship: null}) {
    returning {
      relationship {
        id
        related_text
      }
    }
  }
}

I am getting the following error

"expected an object for type \"B_obj_rel_insert_input\", but found null"

This error does not happen on Hasura 1.3.3.

I wonder if it's related nested inserts (https://hasura.io/docs/latest/graphql/core/databases/postgres/mutations/insert.html#nested-inserts). I also didn't find anything in the release notes for Hasura 2.0.

Thanks

@tirumaraiselvan
Copy link
Contributor

In 2.0, we introduced not allowing null values to column operators. This is based on the discussion here: #704

We also introduced a flag: HASURA_GRAPHQL_V1_BOOLEAN_NULL_COLLAPSE: true for preserving the older behaviour but it doesn't work over columns/relationships. For more details, refer to this comment: #704 (comment)

Unfortunately, the only solution is to rewrite the query as so:

mutation MyMutation {
  insert_tableA(objects: {relationship: {data: {}}}) {
    returning {
      relationship {
        id
        rel_text
      }
    }
  }

@tokestermw
Copy link
Author

Hi @tirumaraiselvan thanks for you response. Good to know the null changes affects inserts too.

Your suggested query did not work either as in this case, related_text is not nullable.

"Not-NULL violation. null value in column \"related_text\" violates not-null constraint"

One thing that works is removing relationship altogether from the query.

mutation MyMutation {
  insert_A(objects: {}) {
    returning {
      relationship {
        id
        related_text
      }
    }
  }
}

But then in the code, we are forced to maintain two separate queries.

@tirumaraiselvan
Copy link
Contributor

tirumaraiselvan commented Sep 6, 2021

Ah, sorry. I thought you wanted to insert a relationship row as well. So, basically you want one query which inserts a parent row and optionally children rows.

One workaround is to make the the objects input field into a variable and if you have only parent row then construct objects: {} and if you have any children then objects: {relationship: {data: {related_text: "asdf"}}}

@nicuveo Any thoughts here?

@nicuveo
Copy link
Contributor

nicuveo commented Sep 14, 2021

Sorry for the delay! Nope, this is not directly related to the boolean collapse: that was simply an oversight during the work towards 2.0 (see below for an detailed explanation). I have a fix, internally; it will be merged soon, and will hopefully be part of the next release, I'll let you know ASAP.


Ok, now, for the behind-the-scenes details.

The GraphQL spec distinguishes between implicit and explicit null values: it's not the same thing, semantically, to omit the value, or to explicitly give it null. We use this to our advantage, in the engine, to distinguish between required and optional arguments: an optional argument can be omitted (implicit null), but could also be internally non-nullable and reject explicit null values: this is indeed what we now do for boolean values. Such a field would, however, still appear nullable in the schema.

When we rewrote the schema generation code and its corresponding input parsers, we made the field for nested inserts optional: the field is nullable in the schema, the relationship can be omitted; but we forgot to make it internally nullable, meaning we erroneously reject explicit null values.

The difference can be seen in the following snippet:

ObjRel -> do
parser <- objectRelationshipInput sourceName otherTableInfo insPerms selPerms updPerms
pure $ P.fieldOptional relFieldName Nothing parser `mapField`
\objRelIns -> IR.AnnInsObj [] [IR.RelIns objRelIns relationshipInfo] []
ArrRel -> do
parser <- P.nullable <$> arrayRelationshipInput sourceName otherTableInfo insPerms selPerms updPerms
pure $ P.fieldOptional relFieldName Nothing parser <&> \arrRelIns -> do
rel <- join arrRelIns
Just $ IR.AnnInsObj [] [] [IR.RelIns rel relationshipInfo | not $ null $ IR._aiInsObj rel]

in the case of array relationships, the parser is correctly constructed with P.fieldOptional and P.nullable, but in the case of object relationship, the P.nullable is missing.

@tokestermw tokestermw changed the title Hasura 2.0: cannot insert NULL on nullable column Hasura 2.0: cannot insert NULL on nullable column (specifically for nested inserts) Sep 14, 2021
@nicuveo
Copy link
Contributor

nicuveo commented Sep 15, 2021

This was automatically closed when the fix was submitted: it will be part of the next release!

@tokestermw

This comment has been minimized.

@seho-dev

This comment has been minimized.

@BenoitRanque
Copy link
Contributor

BenoitRanque commented Jan 26, 2022

@tokestermw @1018715564 both of you encountered the boolean collapse behavior mentioned earlier in this issue.
This is not a bug. The issue for it is found at #704

Hiding your messages as off-topic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants