This post comes out of a brief discussion I had with @akhiltak yesterday.
TL;DR This post outlines one extension we can make to GraphQL to support additional queries.
Right now our implementation of GraphQL can support simple queries which require a lookup using uid
or xid
. To be a general purpose database, we need to support many different types of queries. In this post we will go through the different types of queries that we need to support and how we can represent them in our query language.
The most common type of query is querying by a particular attribute. i.e. check if a given attribute has a particular value.
Example 1
Find me the actor named āAngelina Jolieā. This is representable in GraphQL as follows:
{
film.actor(type.object.name.en: "Angelina Jolie") {
film.actor.film {
film.performance.film {
type.object.name.en
}
}
}
}
A corresponding Cypher query for this would be:
MATCH (a:Actor) -[:ActorFilm]-> (p:Performance) -[:PerformanceFilm]-> (f:Film)
WHERE a.name = "Angelina Jolie"
RETURN p.name
Example 2
A somewhat more complex example, would be finding all musical dramas where the actor was Angelina Jolie.
This is also representable in GraphQL as:
{
film.actor(type.object.name.en: "Angelina Jolie") {
film.actor.film {
film.performance.film {
film.film.genre (type.object.name.en: "Musical Drama")
type.object.name.en
}
}
}
}
A corresponding Cypher query for this would be:
MATCH (a:Actor) -[:ActorFilm]-> (p:Performance) -[:PerformanceFilm]-> (f:Film) -(:FilmGenre)-> (g:Genre)
WHERE a.name = "Angelina Jolie" AND g.name = "Musical Drama"
RETURN p.name
A Gremlin query for the same will be:
g.V().has("name", "Angelina Jolie")
.out("actorfilm").as("f").out("filmgenre").has("name", "Musical Drama")
.select("f").by("name")
Example 3
All actors whose name starts with Angelina. This query cannot be represented in the GraphQL grammar. The following is a proposed extension.
{
film.actor(type.object.name.en: { op: "starts_with", value:"Angelina" }) {
_uid_
type.object.name.en
}
}
A corresponding Cypher query for this would be:
MATCH (a:Actor)
WHERE a.name STARTS WITH "Angelina"
RETURN a._uid_, a.name
Or a gremlin query:
g.V().hasLabel("actor").has("name", startsWith("Angelina")).as("a")
.select("a").by("name")
This extension to GraphQL allows us to add many different operators such as comparison operators (>, <, <=, >= etc.), string operators (starts_with, ends_with, substring, etc.) and geospatial operators.
Something to Consider
However, if we start considering other operators that we would need to support for a general purpose language, such as union, disjunction, grouping it becomes considerably harder to represent them in GraphQL, whereas they are simpler in Cypher or Gremlin. Moreover those languages are considerably easier to understand to the end user (Cypher is just a variant of SQL, and Gremlin is just like LINQ) as opposed to GraphQL. Should we consider that not being the first query language that we support?
Regardless, for now, how does the extension described above sound?