sqlgraphql

Load only the data that's needed from database with Graphql


I'm learning graphql and I think I've spot one flaw in it. Suppose we have schema like this

type Hero {
  name: String
  friends: [Person]
}

type Person {
  name: String
}

and two queries

{
  hero {
    name
    friends {
      name
    }
  }
}

and this

{
  hero {
    name
  }
}

And a relational database that have two corresponding tables Heros and Persons.

If my understanding is right I can't resolve this queries such that for the first query the resulting sql query would be

select Heros.name, Persons.name
from Heros, Persons
where Hero.name = 'Some' and Persons.heroid = Heros.id

And for the second

select Heros.name, Persons.name from Heros

So that only the fields that are really needed for the query would be loaded from the database.

Am I right about that? Also if graphql would have ability to return only the data that's needed for the query, not the data that's valid for full schema I think this would be possible, right?


Solution

  • In Scala implementation(Sangria-grahlQL) you can achieve this by following:

    Suppose this is the client query:

    query BookQuery { 
        Books(id:123) { 
          id 
          title 
          author {
            id
            name
          }
        }
    }
    

    And this is your QueryType in Garphql Server.

    val BooksDataQuery = ObjectType(
        "data_query",
        "Gets books data",
        fields[Repository, Unit](
          Field("Books", ListType(BookType), arguments = bookId :: Nil, resolve = Projector(2, (context, fields) =>{ c.ctx.getBooks(c.arg(bookId), fields).map(res => res)}))
        )
    )
    val BookType = ObjectType( ....)
    val AuthorType = ObjectType( ....)
    
    Repository class:
    
    def getBooks(id: String, projectionFields: Vector[ProjectedName]) {
    /* Here you have the list of fields that client specified in the query. 
        in this cse Book's id, title and author - id, name. 
        The fields are nested, for example author has id and name. In this case author will have sequence of id and name. i.e. above query field will look like:
        Vector(ProjectedName(id,Vector()), ProjectedName(title,Vector()),ProjectedName(author,ProjectedName(id,Vector()),ProjectedName(name,Vector())))
    
        Now you can put your own logic to read and parse fields the collection and make it appropriate for query in database. */
    }
    

    So basically, you can intercept specified fields by client in your QueryType's field resolver.