All Projects → rubensworks → Graphql To Sparql.js

rubensworks / Graphql To Sparql.js

Licence: mit
Converts GraphQL queries to SPARQL queries

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Graphql To Sparql.js

Hypergraphql
GraphQL interface for querying and serving linked data on the Web.
Stars: ✭ 120 (+93.55%)
Mutual labels:  graphql, rdf, semantic-web, sparql
Hypergraphql
GraphQL interface for querying and serving linked data on the Web.
Stars: ✭ 112 (+80.65%)
Mutual labels:  graphql, rdf, semantic-web, sparql
Rdf4j
Eclipse RDF4J: scalable RDF for Java
Stars: ✭ 242 (+290.32%)
Mutual labels:  hacktoberfest, rdf, semantic-web, sparql
Comunica
📬 A knowledge graph querying framework for JavaScript
Stars: ✭ 183 (+195.16%)
Mutual labels:  graphql, hacktoberfest, rdf, sparql
Processor
Ontology-driven Linked Data processor and server for SPARQL backends. Apache License.
Stars: ✭ 54 (-12.9%)
Mutual labels:  sparql, rdf, semantic-web
ontobio
python library for working with ontologies and ontology associations
Stars: ✭ 104 (+67.74%)
Mutual labels:  sparql, rdf, semantic-web
semantic-python-overview
(subjective) overview of projects which are related both to python and semantic technologies (RDF, OWL, Reasoning, ...)
Stars: ✭ 406 (+554.84%)
Mutual labels:  sparql, rdf, semantic-web
SEPA
Get notifications about changes in your SPARQL endpoint.
Stars: ✭ 21 (-66.13%)
Mutual labels:  sparql, rdf, semantic-web
skos-play
SKOS-Play allows to print SKOS files in HTML or PDF. It also embeds xls2rdf to generate RDF from Excel.
Stars: ✭ 58 (-6.45%)
Mutual labels:  sparql, rdf, semantic-web
mobi
Mobi is a decentralized, federated, and distributed graph data platform for teams and communities to publish and discover data, data models, and analytics that are instantly consumable.
Stars: ✭ 41 (-33.87%)
Mutual labels:  sparql, rdf, semantic-web
CSV2RDF
Streaming, transforming, SPARQL-based CSV to RDF converter. Apache license.
Stars: ✭ 48 (-22.58%)
Mutual labels:  sparql, rdf, semantic-web
sparql-proxy
SPARQL-proxy: provides cache, job control, and logging for any SPARQL endpoint
Stars: ✭ 26 (-58.06%)
Mutual labels:  sparql, rdf, semantic-web
everything
The semantic desktop search engine
Stars: ✭ 22 (-64.52%)
Mutual labels:  sparql, rdf, semantic-web
corese
Software platform implementing and extending the standards of the Semantic Web.
Stars: ✭ 55 (-11.29%)
Mutual labels:  sparql, rdf, semantic-web
sparklis
Sparklis is a query builder in natural language that allows people to explore and query SPARQL endpoints with all the power of SPARQL and without any knowledge of SPARQL.
Stars: ✭ 28 (-54.84%)
Mutual labels:  sparql, rdf, semantic-web
ont-api
ONT-API (OWL-API over Apache Jena)
Stars: ✭ 20 (-67.74%)
Mutual labels:  sparql, rdf, semantic-web
LSQ
Linked SPARQL Queries (LSQ): Framework for RDFizing triple store (web) logs and performing SPARQL query extraction, analysis and benchmarking in order to produce datasets of Linked SPARQL Queries
Stars: ✭ 23 (-62.9%)
Mutual labels:  sparql, rdf, semantic-web
Sessel
Document RDFizer for CouchDB
Stars: ✭ 22 (-64.52%)
Mutual labels:  sparql, rdf, semantic-web
LinkedDataHub
The Knowledge Graph notebook. Apache license.
Stars: ✭ 150 (+141.94%)
Mutual labels:  sparql, rdf, semantic-web
Semanticmediawiki
🔗 Semantic MediaWiki turns MediaWiki into a knowledge management platform with query and export capabilities
Stars: ✭ 359 (+479.03%)
Mutual labels:  rdf, semantic-web, sparql

GraphQL to SPARQL

Build Status Coverage Status npm version

A utility package that allows you to convert GraphQL queries to SPARQL or SPARQL algebra, using a 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: Sets the RDF datatype.
  • @language: Sets the RDF language.
  • @id: Identifies the IRI of a term.
  • @reverse Reverses the direction of a property.

Looking for GraphQL-LD?

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

Defining or looking up the id of entities

Using id fields, the id (or subject) of entities can be queried or defined.

Context:

{
    "hero": "http://example.org/hero",
    "HAN_SOLO": "http://example.org/HanSolo",
    "name": "http://example.org/name",
    "friend": "http://example.org/friend"
}

Getting an id

GraphQL:

{
  hero {
    id
    name
  }
}

SPARQL:

SELECT ?hero_name ?hero_id WHERE {
  _:b1 <http://example.org/hero> ?hero_id.
  ?hero_id <http://example.org/name> ?hero_name.
}

Setting a block-scoped id

GraphQL:

{
  hero(_:HAN_SOLO) {
    name
  }
}

SPARQL:

SELECT ?hero_name WHERE {
  _:b1 <http://example.org/hero> <http://example.org/HanSolo>.
  <http://example.org/HanSolo> <http://example.org/name> ?hero_name.
}

Setting an inline id

GraphQL:

{
  friend(_:HAN_SOLO)
  name
}

SPARQL:

SELECT ?name WHERE {
  ?b1 <http://example.org/friend> <http://example.org/HanSolo>;
    <http://example.org/name> ?name.
}

Defining or looking up the graph

Using graph fields, the named graph can be queried or defined.

When graph is used as a field, this will have as side-effect that fields inside the node can be selected from any graph, instead of only the default graph.

Context:

{
    "hero": "http://example.org/hero",
    "EMPIRE": "http://example.org/EMPIRE",
    "name": "http://example.org/name",
    "friend": "http://example.org/friend"
}

Getting a graph

GraphQL:

{
  hero {
    graph
    name
  }
}

SPARQL:

SELECT ?hero_name ?hero_id WHERE {
  _:b1 <http://example.org/hero> ?hero.
  GRAPH ?graph {
    ?hero <http://example.org/name> ?hero_name.
  }
}

Setting a block-scoped graph (1)

GraphQL:

{
  hero {
    graph(_:EMPIRE)
    name
    friend
  }
}

SPARQL:

SELECT ?hero_name WHERE {
  _:b1 <http://example.org/hero> ?hero.
  GRAPH <http://example.org/EMPIRE> {
    ?hero <http://example.org/name> ?hero_name;
          <http://example.org/friend> ?hero_friend.
  }
}

Setting a block-scoped graph (2)

GraphQL:

{
  hero(graph:EMPIRE) {
    name
    friend
  }
}

SPARQL:

SELECT ?hero_name WHERE {
  GRAPH <http://example.org/EMPIRE> {
    _:b1 <http://example.org/hero> ?hero.
    ?hero <http://example.org/name> ?hero_name.
          <http://example.org/friend> ?hero_friend.
  }
}

Setting an inline graph

GraphQL:

{
  friend(graph:EMPIRE)
  name
}

SPARQL:

SELECT ?name WHERE {
  GRAPH <http://example.org/EMPIRE> {
    ?b1 <http://example.org/friend> ?friend;
  }
  ?b1 <http://example.org/name> ?name.
}

Optional fields

By default, all fields that are defined in the query are required to have results. If any of the fields do not produce results, the full query results set will be empty.

However, in some cases you may not be certain that a field will have results. In those cases, you may want to mark a field as optional, using the @optional directive.

Context:

{
    "hero": "http://example.org/hero",
    "name": "http://example.org/name",
    "friend": "http://example.org/friend"
}

GraphQL:

query {
  hero {
    name @optional
    friend @optional
  }
}

SPARQL:

SELECT ?hero_name ?hero_friend WHERE {
  ?b1 <http://example.org/hero> ?hero.
  OPTIONAL { ?hero <http://example.org/name> ?hero_name. }
  OPTIONAL { ?hero <http://example.org/friend> ?hero_friend. }
}

Reversed fields

If you want to reverse the relationship between a parent a child node, you can use the @reverse context option for a field.

Context:

{
    "hero": "http://example.org/hero",
    "name": "http://example.org/name",
    "friend": { "@reverse": "http://example.org/friend" }
}

GraphQL:

query {
  hero {
    friend {
      name
    }
  }
}

SPARQL:

SELECT ?hero_friend_name WHERE {
  ?b1 <http://example.org/hero> ?hero.
  ?hero_friend <http://example.org/friend> ?hero;
    <http://example.org/name> ?hero_friend_name.
}

Alternative fields

If multiple fields are applicable for retrieving a value, then you can define all of them via the alt argument.

Context:

{
    "hero": "http://example.org/hero",
    "name": "http://example.org/name",
    "firstName": "http://example.org/firstName"
}

GraphQL:

{
  hero {
    name(alt: firstName)
  }
}

If you want to define more than one alternative, you can define them in a list like this: name(alt: [firstName, nickName])

SPARQL:

SELECT ?hero_name WHERE {
  ?b1 <http://example.org/hero> ?hero.
  ?hero (<http://example.org/name>|<http://example.org/firstName>) ?hero_name.
}

Converting to tree-based results

Using a tool such as SPARQL-Results+JSON to tree, results from converted queries can be compacted. By default, all values will be considered plural, and values will always be emitted in an array. With the singularizeVariables option, you can specify which values should be singularized and not wrapped in an array anymore.

To simplify this process, graphql-to-sparql allows @single or @plural directives to be added inside the queries to indicate which fields should be singularized and which ones should remain plural. If no directive is present, everything will remain plural. For this, graphql-to-sparql allows an singularizeVariables object to be passed via options, which can then be used by other tools for compaction.

For example:

import {Converter as TreeConverter} from "sparqljson-to-tree";

const singularizeVariables = {};
const algebra = await new Converter().graphqlToSparqlAlgebra('{ hero { name } }', {
  "hero": "http://example.org/hero",
  "name": "http://example.org/name",
  "friends": "http://example.org/friends"
}, { singularizeVariables });

const response =  { ... }; // Passed to some query engine like Comunica

const jsonResult = new TreeConverter().sparqlJsonResultsToTree(response, { singularizeVariables });

Available directives:

Directive Meaning
@single This field will be singular.
@plural This field will be plural.
@single(scope: all) This field and all child fields will be singular.
@plural(scope: all) This field and all child fields will be plural.

By default, all fields all plural. So there is an implicit @plural(scope: all) directive on the query root.

Singularization examples

Singularizing a field

Query:

{
  hero {
    name @single
  }
}

Example output:

[
  {
    "hero": [
      {
        "name": "Alice"
      },
      {
        "name": "Bob"
      }
    ]
  }
]

Singularizing everything

Query:

query @single(scope: all) {
  hero {
    name
  }
}

Example output:

{
  "hero": {
    "name": "Alice"
  }
}

Singularizing everything except for a single field

Query:

query @single(scope: all) {
  hero @plural {
    name
  }
}

Example output:

{
  "hero": [
    {
      "name": "Alice"
    }
  ]
}

License

This software is written by Ruben Taelman.

This code is released under the MIT license.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].