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

@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.

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.