"""API for fetching metadata using an API""" import json from string import Template from http.client import RemoteDisconnected from urllib.error import URLError from flask import Blueprint from flask import jsonify from flask import request from flask import current_app from pyld import jsonld from SPARQLWrapper import JSON, JSONLD, SPARQLWrapper from gn3.db.rdf import RDF_PREFIXES, PREFIXES metadata = Blueprint("metadata", __name__) @metadata.route("/datasets/", methods=["GET"]) def datasets(name): """Fetch a dataset's metadata given it's ACCESSION_ID or NAME""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?dataset ?predicate ?term ; rdf:type dcat:Dataset ; rdfs:label ?datasetName ; dct:identifier ?accesionId ; ex:belongsToInbredSet ?inbredSetName ; gnt:usesNormalization ?normalizationLabel ; dcat:contactPoint ?investigatorName ; xkos:classifiedUnder ?altName ; ex:platform ?platform ; ex:tissue ?tissue . ?platform ?platformPred ?platformObject ; ex:info ?platformInfo . ?tissue rdfs:label ?tissueName ; rdf:type gnc:tissue ; ex:info ?tissueInfo . } WHERE { ?dataset rdf:type dcat:Dataset ; xkos:classifiedUnder ?inbredSet ; rdfs:label ?datasetName ; (rdfs:label|dct:identifier|skos:prefLabel) "$name" . OPTIONAL { ?dataset dct:identifier ?accesionId . } . OPTIONAL { ?inbredSet ^skos:member gnc:Set ; rdfs:label ?inbredSetName . } . OPTIONAL { ?type ^xkos:classifiedUnder ?dataset ; ^skos:member gnc:DatasetType ; skos:prefLabel ?altName . } . OPTIONAL { ?normalization ^gnt:usesNormalization ?dataset ; rdfs:label ?normalizationLabel . } . OPTIONAL { ?investigator foaf:name ?investigatorName ; ^dcat:contactPoint ?dataset . } . OPTIONAL { ?platform ^gnt:usesPlatform ?dataset ; ?platformPred ?platformObject . } . OPTIONAL { ?dataset gnt:hasPlatformInfo ?platformInfo . } . OPTIONAL { ?dataset gnt:hasTissueInfo ?tissueInfo . } . OPTIONAL { ?dataset gnt:hasTissue ?tissue . ?tissue rdfs:label ?tissueName . } . FILTER (!regex(str(?predicate), '(classifiedUnder|usesNormalization|contactPoint|hasPlatformInfo|tissueInfo)', 'i')) . FILTER (!regex(str(?platformPred), '(classifiedUnder|geoSeriesId|hasGoTreeValue)', 'i')) . }""").substitute(prefix=RDF_PREFIXES, name=name)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) frame = { "@context": { "accessRights": "dct:accessRights", "accessionId": "dct:identifier", "acknowledgement": "gnt:hasAcknowledgement", "altLabel": "skos:altLabel", "caseInfo": "gnt:hasCaseInfo", "classifiedUnder": "xkos:classifiedUnder", "contactPoint": "dcat:contactPoint", "created": "dct:created", "data": "@graph", "dcat": "http://www.w3.org/ns/dcat#", "dct": "http://purl.org/dc/terms/", "description": "dct:description", "ex": "http://example.org/stuff/1.0/", "experimentDesignInfo": "gnt:hasExperimentDesignInfo", "foaf": "http://xmlns.com/foaf/0.1/", "foaf": "http://xmlns.com/foaf/0.1/", "geoSeriesId": "gnt:hasGeoSeriesId", "gnt": "http://genenetwork.org/term/", "id": "@id", "inbredSet": "ex:belongsToInbredSet", "info": "ex:info", "label": "rdfs:label", "normalization": "gnt:usesNormalization", "notes": "gnt:hasNotes", "organization": "foaf:Organization", "platform": "ex:platform", "prefLabel": "skos:prefLabel", "processingInfo": "gnt:hasDataProcessingInfo", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "skos": "http://www.w3.org/2004/02/skos/core#", "tissue": "ex:tissue", "title": "dct:title", "type": "@type", "xkos": "http://rdf-vocabulary.ddialliance.org/xkos#", }, "type": "dcat:Dataset", } return jsonld.compact(jsonld.frame(results, frame), frame) # The virtuoso server is misconfigured or it isn't running at all except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/datasets//list", methods=["GET"]) def list_datasets_by_group(group): """List datasets that belong to a given group""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ex:result rdf:type ex:resultType ; ex:totalCount ?totalCount ; ex:currentPage $offset ; ex:items [ rdfs:label ?datasetName ; dct:identifier ?accessionId ; dct:created ?createTime ; dct:title ?title ; ] . } WHERE { { SELECT ?datasetName ?accessionId ?createTime ?title WHERE { ?dataset rdf:type dcat:Dataset ; rdfs:label ?datasetName . ?inbredSet ^skos:member gnc:Set ; ^xkos:classifiedUnder ?dataset ; rdfs:label ?inbredSetName ; skos:prefLabel ?group . ?group bif:contains "$group" . OPTIONAL { ?dataset dct:identifier ?accesionId . } . OPTIONAL { ?dataset dct:created ?createTime . } . OPTIONAL { ?dataset dct:title ?title . } . } ORDER BY ?createTime LIMIT $limit OFFSET $offset } { SELECT (COUNT(DISTINCT ?dataset)/$limit+1 AS ?totalCount) WHERE { ?dataset rdf:type dcat:Dataset ; rdfs:label ?datasetName . ?inbredSet ^skos:member gnc:Set ; ^xkos:classifiedUnder ?dataset ; rdfs:label ?inbredSetName ; skos:prefLabel ?group . ?group bif:contains "$group" . } } } """).substitute(prefix=RDF_PREFIXES, group=group, limit=page_size, offset=page)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) frame = { "@context": { "classifiedUnder": "xkos:classifiedUnder", "created": "dct:created", "data": "@graph", "dct": "http://purl.org/dc/terms/", "ex": "http://example.org/stuff/1.0/", "id": "@id", "title": "dct:title", "name": "rdfs:label", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "type": "@type", "xkos": "http://rdf-vocabulary.ddialliance.org/xkos#", "pages": "ex:totalCount", "result": "ex:result", "results": "ex:items", "resultItem": "ex:resultType", "currentPage": "ex:currentPage", }, "type": "resultItem", } return jsonld.compact( jsonld.frame(results, frame), frame) # The virtuoso server is misconfigured or it isn't running at all except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/datasets/search/", methods=["GET"]) def search_datasets(term): """Search datasets""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ex:result rdf:type ex:resultType ; ex:totalCount ?totalCount ; ex:currentPage $offset ; ex:items [ rdfs:label ?label ; dct:title ?title ; ex:belongsToInbredSet ?inbredSetName ; xkos:classifiedUnder ?datasetType ; ] } WHERE { { SELECT ?dataset ?label ?inbredSetName ?datasetType ?title WHERE { ?dataset rdf:type dcat:Dataset ; rdfs:label ?label ; ?datasetPredicate ?datasetObject ; xkos:classifiedUnder ?inbredSet . ?inbredSet ^skos:member gnc:Set ; rdfs:label ?inbredSetName . ?datasetObject bif:contains "'$term'" . OPTIONAL { ?dataset dct:title ?title . } . OPTIONAL { ?classification ^xkos:classifiedUnder ?dataset ; ^skos:member gnc:DatasetType ; ?typePredicate ?typeName ; skos:prefLabel ?datasetType . } } ORDER BY ?dataset LIMIT $limit OFFSET $offset } { SELECT (COUNT(*)/$limit+1 AS ?totalCount) WHERE { ?dataset rdf:type dcat:Dataset ; ?p ?o . ?o bif:contains "'$term'" . } } } """).substitute(prefix=RDF_PREFIXES, term=term, limit=page_size, offset=page)) return jsonld.frame( json.loads( sparql.queryAndConvert().serialize(format="json-ld")), { "@context": { "data": "@graph", "type": "@type", "id": "@id", "ex": "http://example.org/stuff/1.0/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "dct": "http://purl.org/dc/terms/", "xkos": "http://rdf-vocabulary.ddialliance.org/xkos#", "inbredSet": "ex:belongsToInbredSet", "classifiedUnder": "xkos:classifiedUnder", "dataset": "rdfs:label", "title": "dct:title", "currentPage": "ex:currentPage", "result": "ex:result", "results": "ex:items", "resultItem": "ex:resultType", "pages": "ex:totalCount" }, "type": "resultItem", } ) # The virtuoso server is misconfigured or it isn't running at all except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/publications/", methods=["GET"]) def publications(name): """Fetch a publication's metadata given it's NAME""" try: if "unpublished" in name: name = f"gn:unpublished{name}" else: name = f"pubmed:{name}" sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { $name ?predicate ?object . } WHERE { $name rdf:type fabio:ResearchPaper ; ?predicate ?object . FILTER (!regex(str(?predicate), '(hasPubMedId)', 'i')) . } """).substitute(name=name, prefix=RDF_PREFIXES)) return jsonld.compact( json.loads(sparql.queryAndConvert().serialize(format="json-ld")), { "@context": { "type": "@type", "id": "@id", "dct": "http://purl.org/dc/terms/", "fabio": "http://purl.org/spar/fabio/", "prism": "http://prismstandard.org/namespaces/basic/2.0/", "xsd": "http://www.w3.org/2001/XMLSchema#", "title": "dct:title", "journal": "fabio:Journal", "volume": "prism:volume", "page": "fabio:page", "creator": "dct:creator", "abstract": "dct:abstract", "year": { "@id": "fabio:hasPublicationYear", "@type": "xsd:gYear", }, "month": { "@id": "prism:publicationDate", "@type": "xsd:gMonth" }, }, }) # The virtuoso server is misconfigured or it isn't running at all except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/publications/search/", methods=["GET"]) def search_publications(term): """Search publications""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ex:result rdf:type ex:resultType ; ex:totalCount ?totalCount ; ex:currentPage $offset ; ex:items [ rdfs:label ?publication ; dct:title ?title ; ] } WHERE { { SELECT ?publication ?title ?pmid WHERE { ?pub rdf:type fabio:ResearchPaper ; ?predicate ?object ; dct:title ?title . ?object bif:contains "'$term'" . BIND( STR(?pub) AS ?publication ) . } ORDER BY ?title LIMIT $limit OFFSET $offset } { SELECT (COUNT(*)/$limit+1 AS ?totalCount) WHERE { ?publication rdf:type fabio:ResearchPaper ; ?predicate ?object . ?object bif:contains "'$term'" . } } } """).substitute(prefix=RDF_PREFIXES, term=term, limit=page_size, offset=page)) results = sparql.queryAndConvert() results = json.loads(results.serialize(format="json-ld")) frame = { "@context": PREFIXES | { "data": "@graph", "type": "@type", "id": "@id", "title": "dct:title", "pubmed": "fabio:hasPubMedId", "currentPage": "ex:currentPage", "result": "ex:result", "results": "ex:items", "resultItem": "ex:resultType", "pages": "ex:totalCount", "url": "rdfs:label", }, "type": "resultItem", "paper": { "@type": "fabio:ResearchPaper", "@container": "@index" } } return jsonld.frame(results, frame) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/phenotypes/", methods=["GET"]) def phenotypes(name): """Fetch a phenotype's metadata given it's name""" try: args = request.args dataset = args.get("dataset", "") sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?phenotype ?predicate ?object ; ?pubPredicate ?pubObject ; ex:species ?speciesName ; ex:inbredSet ?inbredSetName ; ex:dataset ?datasetName . } WHERE { ?phenotype skos:altLabel "$name" ; xkos:classifiedUnder ?inbredSet ; ?predicate ?object . ?inbredSet ^xkos:classifiedUnder ?phenotype ; rdfs:label ?inbredSetName ; xkos:generalizes ?species . ?species skos:prefLabel ?speciesName . FILTER (!regex(str(?predicate), '(classifiedUnder)', 'i')) . OPTIONAL { ?publication ^dct:isReferencedBy ?phenotype ; rdf:type fabio:ResearchPaper ; ?pubPredicate ?pubObject . FILTER (!regex(str(?pubPredicate), '(hasPubMedId|type)', 'i')) . } . OPTIONAL { ?dataset rdf:type dcat:Dataset ; xkos:classifiedUnder ?type; rdfs:label "$dataset" ; skos:prefLabel ?datasetName . ?type ^skos:member gnc:DatasetType . FILTER(?type = gnc:Phenotype) . } } """).substitute(prefix=RDF_PREFIXES, name=name, dataset=dataset)) results = json.loads(sparql.queryAndConvert().serialize(format="json-ld")) if not results: return jsonify({}) frame = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "dct": "http://purl.org/dc/terms/", "gnt": "http://genenetwork.org/term/", "fabio": "http://purl.org/spar/fabio/", "xsd": "http://www.w3.org/2001/XMLSchema#", "prism": "http://prismstandard.org/namespaces/basic/2.0/", "gnc": "http://genenetwork.org/category/", "traitName": "skos:altLabel", "trait": "rdfs:label", "altName": "rdfs:altLabel", "description": "dct:description", "abbreviation": "dct:abbreviation", "labCode": "gnt:labCode", "submitter": "gnt:submitter", "contributor": "dct:contributor", "mean": "gnt:mean", "locus": "gnt:locus", "LRS": "gnt:LRS", "references": "dct:isReferencedBy", "additive": "gnt:additive", "sequence": "gnt:sequence", "title": "dct:title", "journal": "fabio:Journal", "volume": "prism:volume", "page": "fabio:page", "creator": "dct:creator", "abstract": "dct:abstract", "year": { "@id": "fabio:hasPublicationYear", "@type": "xsd:gYear", }, "month": { "@id": "prism:publicationDate", "@type": "xsd:gMonth" }, }, "type": "gnc:Phenotype", } return jsonld.compact(jsonld.frame(results, frame), frame) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/phenotypes//", methods=["GET"]) def fetch_phenotype_by_group(group, name): """Fetch a phenotype's metadata given it's name""" try: args = request.args dataset = args.get("dataset", "") sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?phenotype ?predicate ?object ; ?pubPredicate ?pubObject ; ex:species ?speciesName ; ex:inbredSet ?inbredSetName ; ex:dataset ?datasetName . } WHERE { ?phenotype rdfs:label "$name" ; xkos:classifiedUnder ?inbredSet ; ?predicate ?object . ?inbredSet ^xkos:classifiedUnder ?phenotype ; (rdfs:label|skos:prefLabel|gnt:code) "$group" ; xkos:generalizes ?species . ?species skos:prefLabel ?speciesName . FILTER (!regex(str(?predicate), '(classifiedUnder)', 'i')) . OPTIONAL { ?publication ^dct:isReferencedBy ?phenotype ; rdf:type fabio:ResearchPaper ; ?pubPredicate ?pubObject . FILTER (!regex(str(?pubPredicate), '(hasPubMedId|type)', 'i')) . } . OPTIONAL { ?dataset rdf:type dcat:Dataset ; xkos:classifiedUnder ?type; rdfs:label "$dataset" ; skos:prefLabel ?datasetName . ?type ^skos:member gnc:DatasetType . FILTER(?type = gnc:Phenotype) . } } """).substitute(prefix=RDF_PREFIXES, group=group, name=name, dataset=dataset)) results = json.loads(sparql.queryAndConvert().serialize(format="json-ld")) if not results: return jsonify({}) frame = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "dct": "http://purl.org/dc/terms/", "gnt": "http://genenetwork.org/term/", "fabio": "http://purl.org/spar/fabio/", "xsd": "http://www.w3.org/2001/XMLSchema#", "prism": "http://prismstandard.org/namespaces/basic/2.0/", "gnc": "http://genenetwork.org/category/", "traitName": "skos:altLabel", "trait": "rdfs:label", "altName": "rdfs:altLabel", "description": "dct:description", "abbreviation": "dct:abbreviation", "labCode": "gnt:labCode", "submitter": "gnt:submitter", "contributor": "dct:contributor", "mean": "gnt:mean", "locus": "gnt:locus", "LRS": "gnt:LRS", "references": "dct:isReferencedBy", "additive": "gnt:additive", "sequence": "gnt:sequence", "title": "dct:title", "journal": "fabio:Journal", "volume": "prism:volume", "page": "fabio:page", "creator": "dct:creator", "abstract": "dct:abstract", "year": { "@id": "fabio:hasPublicationYear", "@type": "xsd:gYear", }, "month": { "@id": "prism:publicationDate", "@type": "xsd:gMonth" }, }, "type": "gnc:Phenotype", } return jsonld.compact(jsonld.frame(results, frame), frame) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/genotypes/", methods=["GET"]) def genotypes(name): """Fetch a genotype's metadata given it's name""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?genotype ?predicate ?object . ?species rdfs:label ?speciesName . } WHERE { ?genotype rdf:type gnc:Genotype ; rdfs:label "$name" ; ?predicate ?object . OPTIONAL { ?species ^xkos:classifiedUnder ?genotype ; rdfs:label ?speciesName . } } """).substitute(prefix=RDF_PREFIXES, name=name)) results = json.loads(sparql.queryAndConvert().serialize(format="json-ld")) if not results: return jsonify({}) frame = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "gnt": "http://genenetwork.org/term/", "xkos": "http://rdf-vocabulary.ddialliance.org/xkos#", "gnc": "http://genenetwork.org/category/", "xsd": "http://www.w3.org/2001/XMLSchema#", "name": "rdfs:label", "chr": "gnt:chr", "mb": "gnt:mb", "mbMm8": "gnt:mbMm8", "mb2016": "gnt:mb2016", "sequence": "gnt:hasSequence", "source": "gnt:hasSource", "species": "xkos:classifiedUnder", "alternateSource": "gnt:hasAltSourceName", "comments": "rdfs:comments", "chrNum": { "@id": "gnt:chrNum", "@type": "xsd:int", } }, "type": "gnc:Genotype", } return jsonld.compact(jsonld.frame(results, frame), frame) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/genewikis/gn/", methods=["GET"]) def get_gn_genewiki_entries(symbol): """Fetch the GN and NCBI GeneRIF entries""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?symbol ex:entries [ rdfs:comment ?comment ; ex:species ?species_ ; dct:created ?createTime ; dct:references ?pmids ; dct:creator ?creator ; gnt:belongsToCategory ?categories ; ] . ?symbol rdf:type gnc:GNWikiEntry ; ex:totalCount ?totalCount ; ex:currentPage $offset . } WHERE { { SELECT ?symbol ?comment (GROUP_CONCAT(DISTINCT ?speciesName; SEPARATOR='; ') AS ?species_) ?createTime ?creator (GROUP_CONCAT(DISTINCT ?pubmed; SEPARATOR='; ') AS ?pmids) (GROUP_CONCAT(DISTINCT ?category; SEPARATOR='; ') AS ?categories) WHERE { ?symbol rdfs:label ?label ; rdfs:comment _:entry . ?label bif:contains "'$symbol'" . _:entry rdf:type gnc:GNWikiEntry ; rdfs:comment ?comment . OPTIONAL { ?species ^xkos:classifiedUnder _:entry ; ^skos:member gnc:Species ; skos:prefLabel ?speciesName . } . OPTIONAL { _:entry dct:created ?createTime . } . OPTIONAL { _:entry dct:references ?pubmed . } . OPTIONAL { ?investigator foaf:name ?creator ; ^dct:creator _:entry . } . OPTIONAL { _:entry gnt:belongsToCategory ?category . } . } GROUP BY ?comment ?symbol ?createTime ?creator ORDER BY ?createTime LIMIT $limit OFFSET $offset } { SELECT (COUNT(DISTINCT ?comment)/$limit+1 AS ?totalCount) WHERE { ?symbol rdfs:comment _:entry ; rdfs:label ?label . _:entry rdfs:comment ?comment ; rdf:type gnc:GNWikiEntry . ?label bif:contains "'$symbol'" . } } } """).substitute(prefix=RDF_PREFIXES, symbol=symbol, limit=page_size, offset=page)) results = sparql.queryAndConvert() results = json.loads(results.serialize(format="json-ld")) context = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "ex": "http://example.org/stuff/1.0/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "gnt": "http://genenetwork.org/term/", "gnc": "http://genenetwork.org/category/", "dct": "http://purl.org/dc/terms/", "xsd": "http://www.w3.org/2001/XMLSchema#", "entries": "ex:entries", "comment": "rdfs:comment", "species": "ex:species", "category": 'gnt:belongsToCategory', "author": "dct:creator", "pubmed": "dct:references", "currentPage": "ex:currentPage", "pages": "ex:totalCount", "created": { "@id": "dct:created", "@type": "xsd:datetime" }, }, "type": "gnc:GNWikiEntry" } return jsonld.compact( jsonld.frame(results, context), context) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/genewikis/ncbi/", methods=["GET"]) def get_ncbi_genewiki_entries(symbol): """Fetch the NCBI GeneRIF entries""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?symbol ex:entries [ rdfs:comment ?comment ; gnt:hasGeneId ?geneId ; ex:species ?species_ ; dct:created ?createTime ; dct:references ?pmids ; dct:creator ?creator ; ] . ?symbol rdf:type gnc:GNWikiEntry ; ex:totalCount ?totalCount ; ex:currentPage $offset . } WHERE { { SELECT ?symbol ?comment ?geneId (GROUP_CONCAT(DISTINCT ?speciesName; SEPARATOR='; ') AS ?species_) ?createTime ?creator (GROUP_CONCAT(DISTINCT ?pubmed; SEPARATOR='; ') AS ?pmids) WHERE { ?symbol rdfs:label ?label ; rdfs:comment _:entry . ?label bif:contains "'$symbol'" . _:entry rdf:type gnc:NCBIWikiEntry ; rdfs:comment ?comment . OPTIONAL { ?species ^xkos:classifiedUnder _:entry ; ^skos:member gnc:Species ; skos:prefLabel ?speciesName . } . OPTIONAL { _:entry gnt:hasGeneId ?geneId . } . OPTIONAL { _:entry dct:created ?createTime . } . OPTIONAL { _:entry dct:references ?pubmed . } . OPTIONAL { ?investigator foaf:name ?creator ; ^dct:creator _:entry . } . } GROUP BY ?comment ?symbol ?createTime ?creator ?geneId ORDER BY ?createTime LIMIT $limit OFFSET $offset } { SELECT (COUNT(DISTINCT ?comment)/$limit+1 AS ?totalCount) WHERE { ?symbol rdfs:comment _:entry ; rdfs:label ?label . _:entry rdfs:comment ?comment ; rdf:type gnc:NCBIWikiEntry . ?label bif:contains "'$symbol'" . } } } """).substitute(prefix=RDF_PREFIXES, symbol=symbol, limit=page_size, offset=page)) results = sparql.queryAndConvert() results = json.loads(results.serialize(format="json-ld")) context = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "ex": "http://example.org/stuff/1.0/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "gnt": "http://genenetwork.org/term/", "gnc": "http://genenetwork.org/category/", "dct": "http://purl.org/dc/terms/", "xsd": "http://www.w3.org/2001/XMLSchema#", "entries": "ex:entries", "comment": "rdfs:comment", "category": 'gnt:belongsToCategory', "author": "dct:creator", "species": "ex:species", "geneId": "gnt:hasGeneId", "pubmed": "dct:references", "currentPage": "ex:currentPage", "pages": "ex:totalCount", "created": { "@id": "dct:created", "@type": "xsd:datetime" }, }, "type": "gnc:GNWikiEntry" } return jsonld.compact( jsonld.frame(results, context), context) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/species", methods=["GET"]) def list_species(): """List all species""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?species ?predicate ?object . } WHERE { ?species ^skos:member gnc:Species ; ?predicate ?object . VALUES ?predicate { rdfs:label skos:prefLabel skos:altLabel gnt:shortName gnt:family skos:notation } } """).substitute(prefix=RDF_PREFIXES)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) return jsonld.compact(results, { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "gnt": "http://genenetwork.org/term/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "name": "rdfs:label", "family": "gnt:family", "shortName": "gnt:shortName", "alternateName": "skos:altLabel", "taxonomicId": "skos:notation", "fullName": "skos:prefLabel", }, }) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/species/", methods=["GET"]) def fetch_species(name): """Fetch a Single species information""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?species ?predicate ?object . } WHERE { ?species ^skos:member gnc:Species ; gnt:shortName "$name" ; ?predicate ?object . VALUES ?predicate { rdfs:label skos:prefLabel skos:altLabel gnt:shortName gnt:family skos:notation } } """).substitute(prefix=RDF_PREFIXES, name=name)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) return jsonld.compact(results, { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "gnt": "http://genenetwork.org/term/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "name": "rdfs:label", "family": "gnt:family", "shortName": "gnt:shortName", "alternateName": "skos:altLabel", "taxonomicId": "skos:notation", "fullName": "skos:prefLabel", }, }) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/groups", methods=["GET"]) def groups(): """Fetch the list of groups""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?group ?predicate ?object . } WHERE { ?group ^skos:member gnc:Set ; ?predicate ?object . VALUES ?predicate { rdfs:label skos:prefLabel gnt:geneticType gnt:mappingMethod gnt:code gnt:family } } """).substitute(prefix=RDF_PREFIXES)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) return jsonld.compact(results, { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "gnt": "http://genenetwork.org/term/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "name": "rdfs:label", "family": "gnt:family", "shortName": "gnt:shortName", "code": "gnt:code", "mappingMethod": "gnt:mappingMethod", "geneticType": "gnt:geneticType", "fullName": "skos:prefLabel", }, }) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/groups/", methods=["GET"]) def fetch_group_by_species(name): """Fetch the list of groups""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?group ?predicate ?object . } WHERE { ?species gnt:shortName "$name" ; ^skos:member gnc:Species . ?group ^skos:member gnc:Set ; xkos:generalizes ?species ; ?predicate ?object . VALUES ?predicate { rdfs:label skos:prefLabel gnt:geneticType gnt:mappingMethod gnt:code gnt:family } } """).substitute(prefix=RDF_PREFIXES, name=name)) results = sparql.queryAndConvert() results = json.loads( results.serialize(format="json-ld") ) return jsonld.compact(results, { "@context": { "data": "@graph", "type": "@type", "id": "@id", "skos": "http://www.w3.org/2004/02/skos/core#", "gnt": "http://genenetwork.org/term/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "name": "rdfs:label", "family": "gnt:family", "shortName": "gnt:shortName", "code": "gnt:code", "mappingMethod": "gnt:mappingMethod", "geneticType": "gnt:geneticType", "fullName": "skos:prefLabel", }, }) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/genotypes/", methods=["GET"]) def genotypes(name): """Fetch a genotype's metadata given it's name""" try: sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?genotype ?predicate ?object . ?species rdfs:label ?speciesName . } WHERE { ?genotype rdf:type gnc:Genotype ; rdfs:label "$name" ; ?predicate ?object . OPTIONAL { ?species ^xkos:classifiedUnder ?genotype ; rdfs:label ?speciesName . } } """).substitute(prefix=RDF_PREFIXES, name=name)) results = json.loads(sparql.queryAndConvert().serialize(format="json-ld")) if not results: return jsonify({}) frame = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "gnt": "http://genenetwork.org/term/", "xkos": "http://rdf-vocabulary.ddialliance.org/xkos#", "gnc": "http://genenetwork.org/category/", "xsd": "http://www.w3.org/2001/XMLSchema#", "name": "rdfs:label", "chr": "gnt:chr", "mb": "gnt:mb", "mbMm8": "gnt:mbMm8", "mb2016": "gnt:mb2016", "sequence": "gnt:hasSequence", "source": "gnt:hasSource", "species": "xkos:classifiedUnder", "alternateSource": "gnt:hasAltSourceName", "comments": "rdfs:comments", "chrNum": { "@id": "gnt:chrNum", "@type": "xsd:int", } }, "type": "gnc:Genotype", } return jsonld.compact(jsonld.frame(results, frame), frame) except (RemoteDisconnected, URLError): return jsonify({}) @metadata.route("/genewikis/gn/", methods=["GET"]) def get_gn_genewiki_entries(symbol): """Fetch the GN and NCBI GeneRIF entries""" try: args = request.args page = args.get("page", 0) page_size = args.get("per-page", 10) sparql = SPARQLWrapper(current_app.config.get("SPARQL_ENDPOINT")) sparql.setQuery(Template(""" $prefix CONSTRUCT { ?symbol ex:entries [ rdfs:comment ?comment ; ex:species ?species_ ; dct:created ?createTime ; dct:references ?pmids ; dct:creator ?creator ; gnt:belongsToCategory ?categories ; ] . ?symbol rdf:type gnc:GNWikiEntry ; ex:totalCount ?totalCount ; ex:currentPage $offset . } WHERE { { SELECT ?symbol ?comment (GROUP_CONCAT(DISTINCT ?speciesName; SEPARATOR='; ') AS ?species_) ?createTime ?creator (GROUP_CONCAT(DISTINCT ?pubmed; SEPARATOR='; ') AS ?pmids) (GROUP_CONCAT(DISTINCT ?category; SEPARATOR='; ') AS ?categories) WHERE { ?symbol rdfs:label ?label ; rdfs:comment _:entry . ?label bif:contains "'$symbol'" . _:entry rdf:type gnc:GNWikiEntry ; rdfs:comment ?comment . OPTIONAL { ?species ^xkos:classifiedUnder _:entry ; ^skos:member gnc:Species ; skos:prefLabel ?speciesName . } . OPTIONAL { _:entry dct:created ?createTime . } . OPTIONAL { _:entry dct:references ?pubmed . } . OPTIONAL { ?investigator foaf:name ?creator ; ^dct:creator _:entry . } . OPTIONAL { _:entry gnt:belongsToCategory ?category . } . } GROUP BY ?comment ?symbol ?createTime ?creator ORDER BY ?createTime LIMIT $limit OFFSET $offset } { SELECT (COUNT(DISTINCT ?comment)/$limit+1 AS ?totalCount) WHERE { ?symbol rdfs:comment _:entry ; rdfs:label ?label . _:entry rdfs:comment ?comment ; rdf:type gnc:GNWikiEntry . ?label bif:contains "'$symbol'" . } } } """).substitute(prefix=RDF_PREFIXES, symbol=symbol, limit=page_size, offset=page)) results = sparql.queryAndConvert() results = json.loads(results.serialize(format="json-ld")) context = { "@context": { "data": "@graph", "type": "@type", "id": "@id", "ex": "http://example.org/stuff/1.0/", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "gnt": "http://genenetwork.org/term/", "gnc": "http://genenetwork.org/category/", "dct": "http://purl.org/dc/terms/", "xsd": "http://www.w3.org/2001/XMLSchema#", "entries": "ex:entries", "comment": "rdfs:comment", "species": "ex:species", "category": 'gnt:belongsToCategory', "author": "dct:creator", "pubmed": "dct:references", "currentPage": "ex:currentPage", "pages": "ex:totalCount", "created": { "@id": "dct:created", "@type": "xsd:datetime" }, }, "type": "gnc:GNWikiEntry" } return jsonld.compact( jsonld.frame(results, context), context) except (RemoteDisconnected, URLError): return jsonify({})