I'm using Relay endpoints generated in Hasura, connected to a PostgreSQL database.
Suppose there are three objects a
, b
, and c
.
a
has one-to-many relationships with b
s and c
s.c
has a one-to-one relationship with b
. (Exactly one b
for each c
, but not the other way around.)This is the essence of the Relay GraphQL schema for these objects:
type a implements Node {
id: ID!
bs(...): [b!]!
bs_connection(...): bConnection!
cs(...): [c!]!
cs_connection(...): cConnection!
}
type b implements Node {
id: ID!
a: jargon!
a_id: Int!
c: translation
c_id: Int
}
type c implements Node {
id: ID!
b: comment
b_id: Int!
a: jargon!
a_id: Int!
}
I want to insert an object a
with b
and c
altogether:
a --→ b
\ ↑
-→ c
But if I try the followings:
mutation AttemptMutation1 {
insert_a_one(object: {bs: {data: {c: {data: {}}}}}) {
id
}
}
mutation AttemptMutation2 {
insert_a_one(object: {cs: {data: {b: {data: {}}}}}) {
id
}
}
neither works, emitting errors like
Not-NULL violation. null value in column \"b_id\" of relation \"c\" violates not-null constraint
I'm currently resorting to
a
with b
object nested,c
with b
ID, andb
with c
ID.
Here I'm also not sure why step 2 does not set c
ID for b
automatically.
This makes 3 GraphQL queries which really hurts the performance.
Ideally I would like to perform this operation in a single transaction to make it robust.What is the recommended way to deal with this kind of mutation?
I came to the conclusion that this is exactly the case where UUIDs as PKs are the solution. The root cause of this was not knowing the IDs prior to the DB lookup, and by migrating the DBs to use UUIDs as PKs, I have solved this problem.
There are a lot of derived problems related to this after some research, e.g., using a custom @export
directive to use ID as a runtime variable, updating with nested objects, nested relationships in mutation, etc.
But I believe the client being able to choose IDs seem like a occam's razor solution for this problem.