Add support for GQL blank nodes

Hi,

In an older conversation me @amaster507 and @MichelDiz spoke about blank nodes in gql.
@amaster507 and I wanted/suggested the following:

Instead of

(
    input: [
   {
      name: "lucas",
      friendOf: [
         {
            name: "Jorge",
            friendOf: [
               {
                    name: "lucas"
               }
            ]
         }
      ]
   }
  )

It could be like:

addPerson(
    input: [
 {
      uid: "_:Lucas",
      name: "lucas",
      friendOf: [
         {
            uid: "_:Jorge"
         }
      ]
   },
   {
      uid: "_:Jorge",
      name: "jorge",
      friendOf: [
         {
            uid: "_:Lucas"
         }
      ]
   }
    ]
  )

Or:

addPerson(
    input: [
 {
      uid: "_:Lucas",
      name: "lucas"
   },
   {
      uid: "_:Jorge",
      name: "jorge",
      friendOf: [
         {
            uid: "_:Lucas"
         }
      ]
   }
    ]
  )

That’s a view of the organization at transaction level. But the @id directive could do the same thing

Is this something that you can add or already have a solution for?

Thanks,
Spinelsun

2 Likes

@core-devs what do you think about it?

I personally love it. @pawan is in charge of the GraphQL impl and would have more of an idea about the workloads required.

1 Like

We could look into adding this. What’s the advantage of having this over a mutation without any blank nodes? Is it because it gives you an easy way to get the uids of the new nodes added from the assigned map?

Hi,

Its is a bit more than that.
If implemented this feature will allow to create connections between nodes at the same addXXX query.
Now I need to create nodes independently and then make the connections between them or create them in a recursive way like in the example:

(
    input: [
   {
      name: "lucas",
      friendOf: [
         {
            name: "Jorge",
            friendOf: [
               {
                    name: "lucas"
               }
            ]
         }
      ]
   }
  )

Both of the exisiting ways costs a lot in performance and has a huge overhead on development

Could you expand on how they cost a lot in performance, are your mutations slow because of it?

  1. If I choose to go with way number one, I create all of the nodes separately and then connect between them. First, I have to make many more requests to the server, which is inefficient. Second, in my code, I have to loop over data twice, once for constructing the creation query and second for finding edges and update the connections between nodes.
    Think about the complexity if I have data that goes deeper than 2 levels like in the example.
  2. If I choose to go with a recursive query, well recursion almost always has a bad performance. Even if I could optimize the recursion, it will still perform less god than a flat query.

btw I think it will open doors for upserts as well

@pawan what do you think

GraphQL manages that recursion for you because you just have to supply an object. I am still failing to understand how does providing a blank node help to you? I can see some performance optimization as GraphQL won’t have to check if the node already exists and can always assume that it’s a new node. Therefore the overall DQL mutation would be smaller as a result.

Without saying all of this again, here is my recommendation/idea from the related post to this OP:

To chime in on this old feature request, here’s a scenerio that I don’t think is currently possible without supporting blank nodes in GraphQL:

Say I have the following, simplified schema:

type UserAccount {
  id: ID!
  profile: ContactPerson!
}

type OrganizationAccount {
  id: ID!
  profile: ContactOrganization!
}

union Account = UserAccount | OrganizationAccount

interface Contact {
  id: ID!
  owner: Account!
}

type ContactOrganization implements Contact {
  name: String!
}

type ContactPerson implements Contact {
  firstName: String
}

In this schema, UserAccount#profile and OrganizationAccount#profile cannot have @hasInverse(field: owner) because Contact#owner has type Account. Despite this, it is still important that Contact#owner contain the inverse relation to OrganizationAccount#profile or UserAccount#Profile.

I’d like to be able to do the following mutation:

mutation addOrg {
  addOrganizationAccount(
    input: [
      {
        id: "_:orgId"
        profile: {
          name: "Volunteer Center of Santa Cruz County"
          owner: { organizationAccountRef: { id: "_:orgId" } }
        }
      }
    ]
  ) {
    organizationAccount {
      id
    }
  }
}

But at the moment I cannot and it doesn’t appear that there is any way to perform this CRUD action using GraphQL within a transaction. I expect there are other complex queries that can benefit from blank nodes.