Feature Request: Reverse Query for auth rule

Really have been digging into performance of our auth rules this week trying to optimize everything I can on my end.

I have a schema with auth rules such as:

type User @auth(
  query: { or: [
    { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
    { rule: "query ($USERNAME: String!) { queryUser(filter: { username: { eq: $USERNAME } }) { username } }" }
  ]}
  add: { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
  update: { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
  delete: { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
) {
  username: String! @id
  name: String!
  hasNotes: [Note] @hasInverse(field: by)
}

type Note @auth(
  query: { or: [
    { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
    { rule: "query ($USERNAME: String!) { queryNote { user(filter: { username: { eq: $USERNAME } }) { username } } }" }
  ]}
  add: { or: [
    { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
    { rule: "query ($USERNAME: String!) { queryNote { user(filter: { username: { eq: $USERNAME } }) { username } } }" }
  ]}
  update: { or: [
    { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
    { rule: "query ($USERNAME: String!) { queryNote { user(filter: { username: { eq: $USERNAME } }) { username } } }" }
  ]}
  delete: { or: [
    { rule: "{$USERROLE: { eq: \"ADMINISRATOR\" }}" }
    { rule: "query ($USERNAME: String!) { queryNote { user(filter: { username: { eq: $USERNAME } }) { username } } }" }
  ]}
) {
  id: ID
  content: String
  by: User!
}

The concept here is that an administrator would have access to everything globally while a non admin regular user would have full access of their notes and read only access to their own user.

This works. But…

This method uses cascade theoretically on the query rules. Doing this selects ALL of the notes and then reduces from there to only the ones that have the Note.by predicate with the filtered edge.

A more efficient way to make the same query would be to reverse the query and first select the User and then use the User.hasNotes edge unfiltered. This would

  • reduce the footprint at root significantly reducing query times, and
  • remove a filter from an edge which reduces query times.

I understand that this would change how the query rule was applied to the query because right now it is expecting the root to be the same type to where it is applied. To this I have two possible solutions:

  1. Allow a user to define where the type match root is. As auth rules are not stacked on one another anyways, a query rule is querying against an unrestricted dataset. If a user could specify the place where the uid is expected then the dql conversion of the query could use that to tie it to the root type.
@auth( query: { rule: """
  query ($USERNAME: String!) { 
    getUser(username: $USERNAME) {
      hasNotes {
        id @here
      }
    }
  }
""" })
  1. Allow an advanced user to use DQL in auth rules. This would be really nice :smiley:
    a. Propose changing rule usage in a breaking change where rule only applies to RBAC
    b. Propose adding prop query which accepts a GraphQL query with the current type restrictions applied
    c. Propose adding prop dql which accepts a DQL query for advanced users
@auth( query: { dql: """
  query queryNote ($USERNAME: string!) {
    var(func: eq(User.username, $USERNAME)) {
      notes as Contact.hasNotes
    }
    queryNotes(func: uid(notes))
  }
""" })

NOTE: I am not 100% sure of my DQL syntax, I have never used graphql variables, as they are called, in DQL

1 Like

Can you share some queries which are slow for you? We can look at them and see how can we improve their performance. We have found major improvements in the other query that we were looking at for you (which we are going to share soon). We want to see if the effects of the fix also help with these queries.

1 Like

From the work that your team did on the query we sent you already that will most likely solve many other slower queries of the same rules format. I don’t have any other queries at hand that are any worse per se at this time. This OP was in hopes of writing more advanced query rules but that may not be needed seeing the superb results of the work done so far. I do think being able to write DQL queries would be nice for advanced users, but I understand that the demand might not be there for this feature at this time. Thank you again for all of the work you guys have done.