Package Exports
- graphql-to-sparql
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (graphql-to-sparql) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
GraphQL to SPARQL
A utility package that allows you to convert GraphQL queries to SPARQL or SPARQL algebra, using a (simplied) JSON-LD context.
Install
$ npm install [-g] graphql-to-sparql
Usage
The graphql-to-sparql
converts GraphQL queries to SPARQL.
$ graphql-to-sparql '{ "hero": "http://example.org/hero", "name": "http://example.org/name" }' '{ hero { name } }'
$ graphql-to-sparql my-context.jsonld my-query.graphql
The programmatic API can be invoked as follows:
const Converter = require('graphql-to-sparql').Converter;
const algebra = new Converter().graphqlToSparqlAlgebra('{ hero { name } }', {
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"friends": "http://example.org/friends"
});
The resulting object is SPARQL algebra.
Examples
Below you can find a couple of examples of how this library converts GraphQL queries to SPARQL. These examples are based on the GraphQL documentation.
Simple nesting
GraphQL trees are converted to SPARQL graphs by chaining triple patterns.
Context:
{
"me": "http://example.org/me",
"name": "http://example.org/name"
}
GraphQL:
{
me {
name
}
}
SPARQL:
SELECT ?me_name WHERE {
_:b1 <http://example.org/me> ?me.
?me <http://example.org/name> ?me_name.
}
Fields
Nodes can be nested to any depth, and just produce more triple patterns.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"friends": "http://example.org/friends"
}
GraphQL:
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
SPARQL:
SELECT ?hero_name ?hero_friends_name WHERE {
_:b1 <http://example.org/hero> ?hero.
?hero <http://example.org/name> ?hero_name.
?hero <http://example.org/friends> ?hero_friends.
?hero_friends <http://example.org/name> ?hero_friends_name.
}
Arguments
GraphQL allows arguments to be passed to nodes, which are converted to triple objects in SPARQL.
Context:
{
"human": "http://example.org/human",
"id": "http://example.org/id",
"name": "http://example.org/name",
"height": "http://example.org/height"
}
GraphQL:
{
human(id: "1000") {
name
height
}
}
SPARQL:
SELECT ?human_name ?human_height WHERE {
_:b1 <http://example.org/human> ?human.
?human <http://example.org/id> "1000".
?human <http://example.org/name> ?human_name.
?human <http://example.org/height> ?human_height.
}
Aliases
In some cases, you may have clashing variable names in your GraphQL query. For these situations, aliases can be used to make your rename variables.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"episode": "http://example.org/episode",
"EMPIRE": "http://example.org/types/Empire",
"JEDI": "http://example.org/types/Jedi"
}
GraphQL:
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
SPARQL:
SELECT ?empireHero_name ?jediHero_name WHERE {
_:b1 <http://example.org/hero> ?empireHero.
?empireHero <http://example.org/episode> <http://example.org/types/Empire>.
?empireHero <http://example.org/name> ?empireHero_name.
_:b1 <http://example.org/hero> ?jediHero.
?jediHero <http://example.org/episode> <http://example.org/types/Jedi>.
?jediHero <http://example.org/name> ?jediHero_name.
}
Fragments
GraphQL fragments can be used to abstract certain parts of your query tree to reuse them in different places.
GraphQL always applies fragments on certain types, which are translated to RDF http://www.w3.org/1999/02/22-rdf-syntax-ns#type
predicates.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"appearsIn": "http://example.org/appearsIn",
"friends": "http://example.org/friends",
"episode": "http://example.org/episode",
"EMPIRE": "http://example.org/types/Empire",
"JEDI": "http://example.org/types/Jedi"
}
GraphQL:
{
leftComparison: hero(episode: EMPIRE) {
...comparisonFields
}
rightComparison: hero(episode: JEDI) {
...comparisonFields
}
}
fragment comparisonFields on Character {
name
appearsIn
friends {
name
}
}
SPARQL:
SELECT ?leftComparison_name ?leftComparison_appearsIn ?leftComparison_friends_name ?rightComparison_name ?rightComparison_appearsIn ?rightComparison_friends_name WHERE {
_:b1 <http://example.org/hero> ?leftComparison.
?leftComparison <http://example.org/episode> <http://example.org/types/Empire>.
OPTIONAL {
?leftComparison <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> undefined:Character.
?leftComparison <http://example.org/name> ?leftComparison_name.
?leftComparison <http://example.org/appearsIn> ?leftComparison_appearsIn.
?leftComparison <http://example.org/friends> ?leftComparison_friends.
?leftComparison_friends <http://example.org/name> ?leftComparison_friends_name.
}
_:b1 <http://example.org/hero> ?rightComparison.
?rightComparison <http://example.org/episode> <http://example.org/types/Jedi>.
OPTIONAL {
?rightComparison <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> undefined:Character.
?rightComparison <http://example.org/name> ?rightComparison_name.
?rightComparison <http://example.org/appearsIn> ?rightComparison_appearsIn.
?rightComparison <http://example.org/friends> ?rightComparison_friends.
?rightComparison_friends <http://example.org/name> ?rightComparison_friends_name.
}
}
Variables
Defining variables is only supported via the programmatic API (IVariablesDictionary
) at the time of writing.
Variables can be defined to make queries parameterizable, so that the source query does not have to be changed for every single case.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"friends": "http://example.org/friends",
"episode": "http://example.org/episode",
"JEDI": "http://example.org/types/Jedi"
}
GraphQL:
query HeroNameAndFriends($episode: Episode = "JEDI") {
hero(episode: $episode) {
name
friends {
name
}
}
}
SPARQL:
SELECT ?hero_name ?hero_friends_name WHERE {
_:b1 <http://example.org/hero> ?hero.
?hero <http://example.org/episode> <http://example.org/types/Jedi>.
?hero <http://example.org/name> ?hero_name.
?hero <http://example.org/friends> ?hero_friends.
?hero_friends <http://example.org/name> ?hero_friends_name.
}
Directives
Defining variables is only supported via the programmatic API (IVariablesDictionary
) at the time of writing.
Based on the definition of variables, query behaviour can change using GraphQL directives,
such as @include(if: Boolean)
and @skip(if: Boolean)
.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"friends": "http://example.org/friends",
"episode": "http://example.org/episode",
"JEDI": "http://example.org/types/Jedi"
}
GraphQL:
query Hero($episode: Episode, $withFriends: Boolean! = true) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}
SPARQL:
SELECT ?hero_name ?hero_friends_name WHERE {
_:b1 <http://example.org/hero> ?hero.
?hero <http://example.org/episode> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>.
?hero <http://example.org/name> ?hero_name.
?hero <http://example.org/friends> ?hero_friends.
?hero_friends <http://example.org/name> ?hero_friends_name.
}
Inline Fragments
Similar to regular fragments, inline fragments can be used to scope a block to a certain type.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"primaryFunction": "http://example.org/primaryFunction",
"height": "http://example.org/height",
"Droid": "http://example.org/types/Droid",
"Human": "http://example.org/types/Human"
}
GraphQL:
query HeroForEpisode {
hero {
name
... on Droid {
primaryFunction
}
... on Human {
height
}
}
}
SPARQL:
SELECT ?hero_name ?hero_primaryFunction ?hero_height WHERE {
_:b1 <http://example.org/hero> ?hero.
?hero <http://example.org/name> ?hero_name.
OPTIONAL {
?hero <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/types/Droid>.
?hero <http://example.org/primaryFunction> ?hero_primaryFunction.
}
OPTIONAL {
?hero <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/types/Human>.
?hero <http://example.org/height> ?hero_height.
}
}
Meta fields
Some meta fields, such as __typename
can be used to bind to the type of a node.
Context:
{
"search": "http://example.org/search",
"text": "http://example.org/text",
"name": "http://example.org/name",
"Droid": "http://example.org/types/Droid",
"Human": "http://example.org/types/Human"
}
GraphQL:
{
search(text: "an") {
__typename
... on Human {
name
}
... on Droid {
name
}
... on Starship {
name
}
}
}
SPARQL:
SELECT ?search___typename ?search_name ?search_name ?search_name WHERE {
_:b1 <http://example.org/search> ?search.
?search <http://example.org/text> "an".
?search <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?search___typename.
OPTIONAL {
?search <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/types/Human>.
?search <http://example.org/name> ?search_name.
}
OPTIONAL {
?search <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/types/Droid>.
?search <http://example.org/name> ?search_name.
}
OPTIONAL {
?search <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> undefined:Starship.
?search <http://example.org/name> ?search_name.
}
}
Pagination
The magical arguments first
and offset
can be used to respectively set the limit and offset of query results.
Furthermore, the magical totalCount
field will bind to the total number of matches, irrespective of the first
and offset
fields.
Context:
{
"hero": "http://example.org/hero",
"name": "http://example.org/name",
"friends": "http://example.org/friends"
}
GraphQL:
{
hero {
name
friends(first:2 offset:10) {
totalCount
name
}
}
}
SPARQL:
SELECT ?hero_name ?hero_friends_name ?hero_friends_totalCount WHERE {
_:b1 <http://example.org/hero> ?hero.
?hero <http://example.org/name> ?hero_name.
{
SELECT * WHERE {
{
SELECT * WHERE {
?hero <http://example.org/friends> ?hero_friends.
?hero_friends <http://example.org/name> ?hero_friends_name.
}
}
{ SELECT (COUNT(?hero_friends) AS ?hero_friends_totalCount) WHERE { ?hero <http://example.org/friends> ?hero_friends. } }
}
OFFSET 10
LIMIT 2
}
}
License
This software is written by Ruben Taelman.
This code is released under the MIT license.