GithubHelp home page GithubHelp logo

mrgra / graphql-to-sparql.js Goto Github PK

View Code? Open in Web Editor NEW

This project forked from rubensworks/graphql-to-sparql.js

0.0 2.0 0.0 82 KB

Converts GraphQL queries to SPARQL queries

License: MIT License

JavaScript 1.07% TypeScript 98.93%

graphql-to-sparql.js's Introduction

GraphQL to SPARQL

Build Status Coverage Status npm version Greenkeeper badge

A utility package that allows you to convert GraphQL queries to SPARQL or SPARQL algebra, using a (simplied) JSON-LD context. Such queries are also known as GraphQL-LD queries.

Supported JSON-LD context features:

  • Key-value mapping between shorthands and URIs.
  • @type
  • @language
  • @id
  • @reverse

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
  }
}

Selecting by value

While this is not a default feature of GraphQL, this library allows you to select by certain values of properties. This is done using the _ argument, which takes a value.

GraphQL:

{
  name(_:'Han Solo')
  description
}

License

This software is written by Ruben Taelman.

This code is released under the MIT license.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.