diff --git a/server/graphql/graphqlHandler.js b/server/graphql/graphqlHandler.js index ad7f386..50856d1 100644 --- a/server/graphql/graphqlHandler.js +++ b/server/graphql/graphqlHandler.js @@ -10,6 +10,7 @@ const dioptResolvers = require('./resolvers/diopt.resolvers'); const phenotypeOntologyResolvers = require('./resolvers/phenotype-ontology.resolvers'); const pharosResolvers = require('./resolvers/pharos.resolver'); const stringResolvers = require('./resolvers/string.resolvers'); +const dbnsfpResolvers = require('./resolvers/dbnsfp.resolvers'); // Read schema files const clinvarTypeDefs = readFileSync(path.join(__dirname, 'schemas/clinvar.schema.graphql'), 'utf8'); @@ -18,6 +19,7 @@ const dioptTypeDefs = readFileSync(path.join(__dirname, 'schemas/diopt.schema.gr const phenotypeOntologyTypeDefs = readFileSync(path.join(__dirname, 'schemas/phenotype-ontology.schema.graphql'), 'utf8'); const pharosTypeDefs = readFileSync(path.join(__dirname, 'schemas/pharos.schema.graphql'), 'utf8'); const stringTypeDefs = readFileSync(path.join(__dirname, 'schemas/string.schema.graphql'), 'utf8'); +const dbnsfpTypeDefs = readFileSync(path.join(__dirname, 'schemas/dbnsfp.schema.graphql'), 'utf8'); // Combine all schemas const typeDefs = ` @@ -27,6 +29,7 @@ const typeDefs = ` ${phenotypeOntologyTypeDefs} ${pharosTypeDefs} ${stringTypeDefs} + ${dbnsfpTypeDefs} type Query { clinvarByGeneSymbol(symbol: String!): [Clinvar!]! @@ -58,6 +61,9 @@ const typeDefs = ` stringInteractionsByEnsemblId(ensemblId: String!, limit: Int = 100, start: Int = 0): [StringInteraction!]! stringInteractionBetweenProteins(ensemblId1: String!, ensemblId2: String!): StringInteraction + + dbnsfpByVariant(chr: String!, pos: Int!, ref: String!, alt: String!, build: String!): DbNSFP + dbnsfpByPosition(chr: String!, pos: Int!, build: String!, limit: Int = 100, start: Int = 0): [DbNSFP!]! } `; @@ -95,6 +101,9 @@ const rootValue = { stringInteractionsByEnsemblProteinId: stringResolvers.stringInteractionsByEnsemblProteinId, stringInteractionBetweenProteins: stringResolvers.stringInteractionBetweenProteins, + dbnsfpByVariant: dbnsfpResolvers.dbnsfpByVariant, + dbnsfpByPosition: dbnsfpResolvers.dbnsfpByPosition, + // Type resolvers PharosTarget: pharosResolvers.PharosTarget, }; diff --git a/server/graphql/resolvers/dbnsfp.resolvers.js b/server/graphql/resolvers/dbnsfp.resolvers.js new file mode 100644 index 0000000..651a7de --- /dev/null +++ b/server/graphql/resolvers/dbnsfp.resolvers.js @@ -0,0 +1,51 @@ +const DbNSFP = require('../../models/dbNSFP.model'); + +/** + * dbNSFP GraphQL resolvers + */ +const dbnsfpResolvers = { + // Root query resolvers + dbnsfpByVariant: async (args) => { + try { + const { chr, pos, ref, alt, build } = args; + let query = {}; + if (build === 'hg19') { + query = { hg19Chr: chr, hg19Pos: pos, ref, alt }; + } else if (build === 'hg38') { + query = { hg38Chr: chr, hg38Pos: pos, ref, alt }; + } else { + throw new Error(`Unsupported build: ${build}. Use 'hg19' or 'hg38'`); + } + + const variant = await DbNSFP.findOne(query); + return variant; + } catch (error) { + console.error('Error in dbnsfpByVariant resolver:', error); + throw error; + } + }, + + dbnsfpByPosition: async (args) => { + try { + const { chr, pos, build, limit = 100, start = 0 } = args; + let query = {}; + if (build === 'hg19') { + query = { hg19Chr: chr, hg19Pos: pos }; + } else if (build === 'hg38') { + query = { hg38Chr: chr, hg38Pos: pos }; + } else { + throw new Error(`Unsupported build: ${build}. Use 'hg19' or 'hg38'`); + } + const variants = await DbNSFP + .find(query) + .skip(start) + .limit(limit); + return variants; + } catch (error) { + console.error('Error in dbnsfpByPosition resolver:', error); + throw error; + } + } +}; + +module.exports = dbnsfpResolvers; diff --git a/server/graphql/schemas/dbnsfp.schema.graphql b/server/graphql/schemas/dbnsfp.schema.graphql new file mode 100644 index 0000000..aa8bfa7 --- /dev/null +++ b/server/graphql/schemas/dbnsfp.schema.graphql @@ -0,0 +1,85 @@ +""" +A variant annotation score from a prediction tool +""" +type PredictionScore { + scores: [Float] + predictions: [String] + rankscore: Float +} + +""" +A single prediction score (for tools that don't have multiple transcripts) +""" +type SinglePredictionScore { + score: Float + prediction: String + rankscore: Float +} + +""" +CADD scores (different structure) +""" +type CADDScore { + rawScore: Float + phred: Float + rankscore: Float +} + +""" +REVEL scores (scores only, no predictions) +""" +type REVELScore { + scores: [Float] + rankscore: Float +} + +""" +Conservation scores (score only) +""" +type ConservationScore { + score: Float + rankscore: Float +} + +""" +All prediction scores for a variant +""" +type DbNSFPScores { + SIFT: PredictionScore + SIFT4G: PredictionScore + Polyphen2HDIV: PredictionScore + Polyphen2HVAR: PredictionScore + MutationTaster: PredictionScore + MutationAssessor: PredictionScore + CADD: CADDScore + REVEL: REVELScore + AlphaMissense: PredictionScore + PrimateAI: SinglePredictionScore + MCAP: SinglePredictionScore + GERPppRS: ConservationScore + phyloP100way_vertebrate: ConservationScore + phyloP470way_mammalian: ConservationScore +} + +""" +A dbNSFP variant annotation entry +""" +type DbNSFP { + hg38Chr: String! + hg38Pos: Int! + ref: String! + alt: String! + hg19Chr: String + hg19Pos: Int + hg18Chr: String + hg18Pos: Int + aaPos: Int + aaRef: String + aaAlt: String + rsid: String + ensemblId: String + transcriptEnsemblId: String + proteinEnsemblId: String + symbol: String + scores: DbNSFPScores! +} \ No newline at end of file