From fbb1f36e2efdb834bb47e79b88a97443d6caf1a8 Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Wed, 31 Mar 2021 15:13:46 -0400 Subject: [PATCH 01/13] DTO Classes stopped showing up --- src/TCRD.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TCRD.js b/src/TCRD.js index fd4d72b..67ece9b 100644 --- a/src/TCRD.js +++ b/src/TCRD.js @@ -1724,7 +1724,8 @@ a.*,b.parent_id from do a, do_parent b where a.doid = b.doid`)); getDTO(args) { let matches = []; if (args.dtoid) { - let n = this.dto[args.dtoid]; + const dtoFormat = args.dtoid.replace('_',':'); + let n = this.dto[dtoFormat]; while (n) { matches.push(n); n = n.parent; From e141bba4d8284cd57ce2df7fe8df48577abd1034 Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Fri, 2 Apr 2021 00:37:57 -0400 Subject: [PATCH 02/13] add endpoint for tiga data --- src/models/DataModelList.ts | 4 +-- src/models/queryDefinition.ts | 4 +-- src/resolvers.js | 47 +++++++++++++++++++++++++++++++++++ src/schema.graphql | 26 +++++++++++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/models/DataModelList.ts b/src/models/DataModelList.ts index 4bd677b..b8a1173 100644 --- a/src/models/DataModelList.ts +++ b/src/models/DataModelList.ts @@ -157,7 +157,7 @@ export abstract class DataModelList implements IBuildable { return query; }; - getListQuery() { + getListQuery(innerJoinAll: boolean = false) { let dataFields: FieldInfo[]; if (this.fields && this.fields.length > 0) { dataFields = this.GetDataFields('list'); @@ -172,7 +172,7 @@ export abstract class DataModelList implements IBuildable { const queryDefinition = QueryDefinition.GenerateQueryDefinition(this, dataFields); - const query = queryDefinition.generateBaseQuery(false); + const query = queryDefinition.generateBaseQuery(innerJoinAll); this.addFacetConstraints(query, this.filteringFacets); this.addModelSpecificFiltering(query, true, this.dataFields.map(f => f.table)); diff --git a/src/models/queryDefinition.ts b/src/models/queryDefinition.ts index 19f5a99..3b8d4f1 100644 --- a/src/models/queryDefinition.ts +++ b/src/models/queryDefinition.ts @@ -144,7 +144,7 @@ export class QueryDefinition { return dataTable.tableName === this.buildable.rootTable && dataTable.alias === this.buildable.rootTable; } - generateBaseQuery(forFacet: boolean){ + generateBaseQuery(innerJoinAll: boolean){ const buildableObj = this.buildable; let rootTableObject = this.getRootTable(); if (rootTableObject == undefined) { @@ -161,7 +161,7 @@ export class QueryDefinition { return; } let joinFunction = 'leftJoin'; - if(forFacet || this.buildable.tableNeedsInnerJoin(dataTable)){ + if(innerJoinAll || this.buildable.tableNeedsInnerJoin(dataTable)){ joinFunction = 'join'; } let leftTable = rootTableObject; diff --git a/src/resolvers.js b/src/resolvers.js index 864aa6e..7af2ce8 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -803,6 +803,53 @@ const resolvers = { }); }, + gwasAnalytics: async function (target, args, {dataSources}) { + const geneFieldMap = new Map([ + ['TIGA ENSG ID', 'ensgID'], + ['Trait Count for Gene', 'traitCount'], + ['Study Count for Gene', 'studyCount']]); + const assocFieldMap = new Map([ + ['EFO ID', 'efoID'], + ['GWAS Trait', 'trait'], + ['Study Count', 'studyCount'], + ['SNP Count', 'snpCount'], + ['Weighted SNP Count', 'wSnpCount'], + ['Gene Count for Trait', 'geneCountForTrait'], + ['Study Count for Trait', 'studyCountForTrait'], + ['Median p-value', 'medianPvalue'], + ['Median Odds Ratio', 'medianOddsRatio'], + ['Beta Count', 'betaCount'], + ['Mean Study N', 'meanStudyN'], + ['RCRAS', 'rcras'], + ['Mean Rank', 'meanRank'], + ['Mean Rank Score', 'meanRankScore'] + ]); + const targetList = new TargetList( + dataSources.tcrd, + { + batch: [target.uniprot], + fields: [...Array.from(geneFieldMap.keys()), ...Array.from(assocFieldMap.keys())], + filter: {order: '!Mean Rank Score'} + }); + return targetList.getListQuery(true).then(rows => { + if(!rows || rows.length === 0) { + return null; + } + const gwasObj = {}; + geneFieldMap.forEach((v,k) => { + gwasObj[v] = rows[0][k]; + }); + gwasObj.associations = []; + rows.forEach(row => { + const assoc = {}; + assocFieldMap.forEach((v,k) => { + assoc[v] = row[k]; + }); + gwasObj.associations.push(assoc); + }); + return gwasObj; + }) + }, goCounts: async function (target, _, {dataSources}) { return dataSources.tcrd.getGOCountsForTarget(target) .then(rows => { diff --git a/src/schema.graphql b/src/schema.graphql index f94e419..e58eef7 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -507,6 +507,8 @@ type Target @cacheControl(maxAge: 604800){ gwasCounts: [IntProp] gwas(skip: Int=0, top: Int=10, filter: IFilter): [GWAS] + gwasAnalytics: GwasTargetAnalytics + """GO terms""" goCounts: [IntProp] go(skip: Int=0, top: Int=20, filter: IFilter): [GO] @@ -538,6 +540,30 @@ type Target @cacheControl(maxAge: 604800){ facetValues(facetName: String!, skip: Int=0, top: Int=10): [String] } +type GwasTargetAnalytics @cacheControl(maxAge: 604800) { + ensgID: String + traitCount: Int + studyCount: Int + associations: [GwasTargetAssociation] +} + +type GwasTargetAssociation @cacheControl(maxAge: 604800) { + trait: String + efoID: String + studyCount: Int + snpCount: Int + wSnpCount: Float + geneCountForTrait: Int + studyCountForTrait: Int + medianPvalue: Float + medianOddsRatio: Float + betaCount: Int + meanStudyN: Float + rcras: Float + meanRank: Float + meanRankScore: Float +} + type SimilarTargetResult @cacheControl(maxAge: 604800) { protein_id: Int sym: String From 78abf114fc10da766452b87d2abaa5d0e5fda4a2 Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Fri, 9 Apr 2021 00:04:28 -0400 Subject: [PATCH 03/13] add endpoint for tiga for diseases --- src/TCRD.js | 5 ++++ src/resolvers.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++ src/schema.graphql | 27 ++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/src/TCRD.js b/src/TCRD.js index 67ece9b..1dd35a6 100644 --- a/src/TCRD.js +++ b/src/TCRD.js @@ -470,6 +470,11 @@ OR b.id = (SELECT protein_id FROM xref where xtype = 'Ensembl' and value = ? lim and b.geneid=?`, [args.geneid])); } + if (args.protein_id) { + return this.db.select(this.db.raw(TARGET_SQL + ` +and b.id=?`, [args.protein_id])); + } + return this.db.select(this.db.raw(TARGET_SQL + ` and a.id = ?`, [args.tcrdid])); } diff --git a/src/resolvers.js b/src/resolvers.js index 7af2ce8..40fa3c0 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -809,6 +809,7 @@ const resolvers = { ['Trait Count for Gene', 'traitCount'], ['Study Count for Gene', 'studyCount']]); const assocFieldMap = new Map([ + ['TIGA Disease ID', 'ncats_disease_id'], ['EFO ID', 'efoID'], ['GWAS Trait', 'trait'], ['Study Count', 'studyCount'], @@ -845,6 +846,7 @@ const resolvers = { assocFieldMap.forEach((v,k) => { assoc[v] = row[k]; }); + assoc.linksToDisease = !!assoc.ncats_disease_id; gwasObj.associations.push(assoc); }); return gwasObj; @@ -1280,6 +1282,65 @@ const resolvers = { }).catch(function (error) { console.error(error); }); + }, + gwasAnalytics: async function (disease, args, {dataSources}) { + const traitFieldMap = new Map([ + ['EFO ID', 'efoID'], + ['GWAS Trait', 'trait'], + ['Gene Count for Trait', 'geneCount'], + ['Study Count for Trait', 'studyCount'] + ]); + const assocFieldMap = new Map([ + ['TIGA Protein ID', 'protein_id'], + ['TIGA ENSG ID', 'ensgID'], + ['Study Count', 'studyCount'], + ['SNP Count', 'snpCount'], + ['Weighted SNP Count', 'wSnpCount'], + ['Trait Count for Gene', 'traitCountForGene'], + ['Study Count for Gene', 'studyCountForGene'], + ['Median p-value', 'medianPvalue'], + ['Median Odds Ratio', 'medianOddsRatio'], + ['Beta Count', 'betaCount'], + ['Mean Study N', 'meanStudyN'], + ['RCRAS', 'rcras'], + ['Mean Rank', 'meanRank'], + ['Mean Rank Score', 'meanRankScore'] + ]); + const diseaseList = new DiseaseList( + dataSources.tcrd, + { + batch: [disease.name], + fields: [...Array.from(traitFieldMap.keys()), ...Array.from(assocFieldMap.keys())], + filter: {order: '!Mean Rank Score'} + }); + return diseaseList.getListQuery(true).then(rows => { + if(!rows || rows.length === 0) { + return null; + } + const gwasObj = {}; + traitFieldMap.forEach((v,k) => { + gwasObj[v] = rows[0][k]; + }); + gwasObj.associations = []; + rows.forEach(row => { + const assoc = {}; + assocFieldMap.forEach((v,k) => { + assoc[v] = row[k]; + }); + gwasObj.associations.push(assoc); + }); + return gwasObj; + }); + } + }, + GwasDiseaseAssociation: { + target: async function (gwasData, args, {dataSources}) { + return dataSources.tcrd.getTarget({protein_id: gwasData.protein_id}) + .then(rows => { + return rows[0]; + }).catch(function (error) { + console.error(error); + }); } }, diff --git a/src/schema.graphql b/src/schema.graphql index e58eef7..df696ec 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -191,6 +191,7 @@ type Disease @cacheControl(maxAge: 604800) { parents: [Disease] children: [Disease] tinx: [TINXTarget] + gwasAnalytics: GwasDiseaseAnalytics } type DiseaseID @cacheControl(maxAge: 604800){ @@ -562,6 +563,32 @@ type GwasTargetAssociation @cacheControl(maxAge: 604800) { rcras: Float meanRank: Float meanRankScore: Float + linksToDisease: Boolean +} + +type GwasDiseaseAnalytics @cacheControl(maxAge: 604800) { + efoID: String + trait: String + geneCount: Int + studyCount: Int + associations: [GwasDiseaseAssociation] +} + +type GwasDiseaseAssociation @cacheControl(maxAge: 604800) { + target: Target + ensgID: String + studyCount: Int + snpCount: Int + wSnpCount: Float + traitCountForGene: Int + studyCountForGene: Int + medianPvalue: Float + medianOddsRatio: Float + betaCount: Int + meanStudyN: Float + rcras: Float + meanRank: Float + meanRankScore: Float } type SimilarTargetResult @cacheControl(maxAge: 604800) { From 25544cdb0aa74116e0673cc41200016e7a3506fa Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Mon, 12 Apr 2021 17:52:09 -0400 Subject: [PATCH 04/13] map EFO to disease name --- src/resolvers.js | 60 +++++++++++++++++++++------------------------- src/schema.graphql | 5 +--- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/resolvers.js b/src/resolvers.js index 40fa3c0..2ff6d88 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -31,13 +31,13 @@ const resolvers = { const pieces = listKey.split('-'); const reqModel = args.modelName ? args.modelName.toLowerCase() : ''; const reqAssocModel = args.associatedModelName ? args.associatedModelName.toLowerCase() : ''; - if (pieces[1] != 'download'){ // must be download lists + if (pieces[1] != 'download') { // must be download lists return false; } if (pieces[0] != reqModel) { // must match the model return false; } - if (pieces[2] == ''){ // normal fields should apply no matter the associated model + if (pieces[2] == '') { // normal fields should apply no matter the associated model return true; } if (pieces[2] == reqAssocModel) { // otherwise, have to have the right associated model, or be for a single entity @@ -54,7 +54,7 @@ const resolvers = { try { if (args.top) { args.top = Math.min(args.top, 250000); - }else{ + } else { args.top = 250000; } listObj = DataModelListFactory.getListObject(args.model, dataSources.tcrd, args); @@ -278,17 +278,17 @@ const resolvers = { } }; const model = tryUnbatch(); - if(model == 'targets'){ + if (model == 'targets') { return getTargetResult(args, dataSources).then(res => { return {targetResult: res}; }) } - if(model == 'diseases'){ + if (model == 'diseases') { return getDiseaseResult(args, dataSources.tcrd).then(res => { return {diseaseResult: res}; }) } - if(model == 'ligands'){ + if (model == 'ligands') { return getLigandResult(args, dataSources.tcrd).then(res => { return {ligandResult: res}; }) @@ -809,7 +809,7 @@ const resolvers = { ['Trait Count for Gene', 'traitCount'], ['Study Count for Gene', 'studyCount']]); const assocFieldMap = new Map([ - ['TIGA Disease ID', 'ncats_disease_id'], + ['TIGA Disease Link', 'ncats_disease_id'], ['EFO ID', 'efoID'], ['GWAS Trait', 'trait'], ['Study Count', 'studyCount'], @@ -833,20 +833,19 @@ const resolvers = { filter: {order: '!Mean Rank Score'} }); return targetList.getListQuery(true).then(rows => { - if(!rows || rows.length === 0) { + if (!rows || rows.length === 0) { return null; } const gwasObj = {}; - geneFieldMap.forEach((v,k) => { + geneFieldMap.forEach((v, k) => { gwasObj[v] = rows[0][k]; }); gwasObj.associations = []; rows.forEach(row => { const assoc = {}; - assocFieldMap.forEach((v,k) => { + assocFieldMap.forEach((v, k) => { assoc[v] = row[k]; }); - assoc.linksToDisease = !!assoc.ncats_disease_id; gwasObj.associations.push(assoc); }); return gwasObj; @@ -1314,17 +1313,17 @@ const resolvers = { filter: {order: '!Mean Rank Score'} }); return diseaseList.getListQuery(true).then(rows => { - if(!rows || rows.length === 0) { + if (!rows || rows.length === 0) { return null; } const gwasObj = {}; - traitFieldMap.forEach((v,k) => { + traitFieldMap.forEach((v, k) => { gwasObj[v] = rows[0][k]; }); gwasObj.associations = []; rows.forEach(row => { const assoc = {}; - assocFieldMap.forEach((v,k) => { + assocFieldMap.forEach((v, k) => { assoc[v] = row[k]; }); gwasObj.associations.push(assoc); @@ -1343,25 +1342,20 @@ const resolvers = { }); } }, - - DiseaseAssociation: { - targetCounts: async function (disease, _, {dataSources}) { // TODO: this really doesn't belong here, it recalculates the same thing for all the associations, I left a stub so that it doesn't break with the client, please delete it, oh great and powerful future developer - return resolvers.Disease.targetCounts(disease, _, {dataSources}) - .then(rows => { - return rows; - }) - .catch(function (error) { - console.error(error); - }); - }, - targets: async function (disease, args, {dataSources}) { // TODO: this too - return resolvers.Disease.targets(disease, args, {dataSources}) - .then(rows => { - return rows; - }) - .catch(function (error) { - console.error(error); - }); + GwasTargetAssociation: { + diseaseName: async function (gwasData, args, {dataSources}) { + if (!!gwasData.ncats_disease_id) { + const query = dataSources.tcrd.db('ncats_disease') + .select({name: 'name'}) + .where('id', gwasData.ncats_disease_id); + return query.then(rows => { + if (rows.length > 0) { + return rows[0].name; + } + return null; + }); + } + return null; } }, diff --git a/src/schema.graphql b/src/schema.graphql index df696ec..ab82f88 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -216,9 +216,6 @@ type DiseaseAssociation @cacheControl(maxAge: 604800) { pvalue: Float score: Float source: String - - targetCounts: [IntProp] @deprecated(reason: "use Disease.targetCounts") - targets (skip: Int=0, top: Int=10, filter: IFilter): [Target] @deprecated(reason:"use Disease.targets - each association only has one target anyway") } """Target relationships such as PPI""" @@ -563,7 +560,7 @@ type GwasTargetAssociation @cacheControl(maxAge: 604800) { rcras: Float meanRank: Float meanRankScore: Float - linksToDisease: Boolean + diseaseName: String } type GwasDiseaseAnalytics @cacheControl(maxAge: 604800) { From 80b13734ca5f3782e9cd505b821352ec303341ea Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Fri, 16 Apr 2021 01:00:20 -0400 Subject: [PATCH 05/13] return data sources for harmonizome, and urls --- src/TCRD.js | 2 +- src/resolvers.js | 9 ++++----- src/schema.graphql | 5 +++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/TCRD.js b/src/TCRD.js index 1dd35a6..22cc921 100644 --- a/src/TCRD.js +++ b/src/TCRD.js @@ -978,7 +978,7 @@ and b.target_id = ?`, [target.tcrdid])); } let q = this.db.select(this.db.raw(p + ` as name, -avg(a.attr_cdf) as value +avg(a.attr_cdf) as value, group_concat(distinct concat(b.name,'!',b.url) order by b.name separator '|') as sources from hgram_cdf a, gene_attribute_type b, t2tc c where a.protein_id = c.protein_id and c.target_id = ? diff --git a/src/resolvers.js b/src/resolvers.js index 2ff6d88..65a0973 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -1587,17 +1587,16 @@ const resolvers = { let values = new Map(); rows.forEach(r => { - values.set(r.name, r.value); + values.set(r.name, {value: r.value, sources: r.sources.split('|')}); }); let stats = []; map.forEach(r => { let v = values.get(r); - if (v) { - } else { - v = 0; + if (!v) { + v = {value: 0}; } - stats.push({name: r, value: v}); + stats.push({name: r, value: v.value, sources: v.sources}); }); return stats; diff --git a/src/schema.graphql b/src/schema.graphql index ab82f88..b80919f 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -42,9 +42,10 @@ type IntProp @cacheControl(maxAge: 604800) { value: Int! } -type FloatProp @cacheControl(maxAge: 604800) { +type HSummaryProp @cacheControl(maxAge: 604800) { name: String! value: Float! + sources: [String] } type TemporalCount @cacheControl(maxAge: 604800) { @@ -300,7 +301,7 @@ type Harmonizome @cacheControl(maxAge: 604800) { count: Int attrs: [GeneAttribute] """which must be one of 'type', 'group', or 'category'""" - summary (which: String="type"): [FloatProp] + summary (which: String="type"): [HSummaryProp] } type GeneAttribute @cacheControl(maxAge: 604800) { From 87cf9cd1a2825d6f1c528c9877627b876bd0a14b Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Mon, 19 Apr 2021 23:10:46 -0400 Subject: [PATCH 06/13] clarify TCRD upgrade instructions --- pharos_database_transforms/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pharos_database_transforms/README.md b/pharos_database_transforms/README.md index f4006fa..a6abe0d 100644 --- a/pharos_database_transforms/README.md +++ b/pharos_database_transforms/README.md @@ -33,14 +33,17 @@ Here's what that looks like for our AWS server USER = 'ncats' PWORD = '' ``` -4. Run the pharos specific transformations - * Run these python files at the terminal, they will use credentials from credentials.py to update the database +4. Run the pharos specific transformations + * all of these have been moved to pharos-etl repo, go there to do the knex migrations + The only one here that you might want to do is the lychi one if the drug tables have changed + * ~~Run these python files at the terminal, they will use credentials from credentials.py to update the database~~ - * First + * ~~First~~ * create indices and columns necessary for pharos ``` python executeSQLfile.py tcrd-create-indexes.sql ``` + * Second * Populate lychi_h4 keys for all ligands and drugs * write smiles to files @@ -67,7 +70,7 @@ Here's what that looks like for our AWS server python lychi-set.py ``` - * Later + * ~~Later~~ * create and populate the table that hold the lists of IDG targets ``` python executeSQLfile.py tcrd-create-idg-lists.sql @@ -98,7 +101,7 @@ Here's what that looks like for our AWS server ``` python tcrd-create-generif-pubmed-map.py ``` - * Later still + * ~~Later still~~ * create mapping between data sources and all the targets, diseases, and ligands we have data from there for ``` python tcrd-create-datasource-table.py From 4f7eb70505dd15a5d077e8d052d4774e45b01744 Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Mon, 19 Apr 2021 23:15:01 -0400 Subject: [PATCH 07/13] fix TIGA data model return IDG resources from TCRD --- src/models/target/targetDetails.ts | 13 +++++++++++++ src/resolvers.js | 23 ++++++++++++++++++----- src/schema.graphql | 14 ++++++++++---- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/models/target/targetDetails.ts b/src/models/target/targetDetails.ts index 376304b..e74a285 100644 --- a/src/models/target/targetDetails.ts +++ b/src/models/target/targetDetails.ts @@ -61,4 +61,17 @@ export class TargetDetails{ .orderBy(['startResidue', 'endResidue']); return query; } + + static LD2JSON(ldObject: any){ + const jsonObject: any = {}; + for (const prop in ldObject) { + if (ldObject[prop]['@value']) { + jsonObject[prop] = ldObject[prop]['@value']; + } + else if (ldObject[prop]['rdfs:label']) { + jsonObject[prop] = ldObject[prop]['rdfs:label']; + } + } + return jsonObject; + } } diff --git a/src/resolvers.js b/src/resolvers.js index 65a0973..f660ba3 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -804,15 +804,15 @@ const resolvers = { }, gwasAnalytics: async function (target, args, {dataSources}) { - const geneFieldMap = new Map([ - ['TIGA ENSG ID', 'ensgID'], - ['Trait Count for Gene', 'traitCount'], - ['Study Count for Gene', 'studyCount']]); + const geneFieldMap = new Map([]); // there aren't any that are the same across all associations because they may be from different ensg's const assocFieldMap = new Map([ + ['TIGA ENSG ID', 'ensgID'], + ['Trait Count for Gene', 'traitCountForGene'], + ['Study Count for Gene', 'studyCountForGene'], ['TIGA Disease Link', 'ncats_disease_id'], ['EFO ID', 'efoID'], ['GWAS Trait', 'trait'], - ['Study Count', 'studyCount'], + ['Study Count', 'studyCountForAssoc'], ['SNP Count', 'snpCount'], ['Weighted SNP Count', 'wSnpCount'], ['Gene Count for Trait', 'geneCountForTrait'], @@ -1008,6 +1008,19 @@ const resolvers = { return targetDetails.getAllFacetValues().then(results => { return results.map(res => res.value); }); + }, + drgc_resources: async function (target, args, {dataSources}) { + const query = dataSources.tcrd.db('drgc_resource') + .select({resourceType: 'resource_type', detailBlob: 'json'}) + .where('target_id', target.tcrdid); + return query.then(rows => { + return rows.map(row => { + return { + resourceType: row.resourceType, + detailBlob: TargetDetails.LD2JSON(JSON.parse(row.detailBlob)) + }; + }); + }); } }, SimilarityDetails: { diff --git a/src/schema.graphql b/src/schema.graphql index b80919f..c744c39 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -423,11 +423,17 @@ type SeqAnnotationInfo @cacheControl(maxAge: 604800){ name: String } +type DRGCResource @cacheControl(maxAge: 604800){ + resourceType: String + detailBlob: JSON +} + """Target entity""" type Target @cacheControl(maxAge: 604800){ similarity: SimilarityDetails sequence_variants: SeqVariantInfo sequence_annotations: [SeqAnnotationInfo] + drgc_resources: [DRGCResource] """Internal TCRD ID; should not be used externally!""" tcrdid: Int! @@ -540,16 +546,16 @@ type Target @cacheControl(maxAge: 604800){ } type GwasTargetAnalytics @cacheControl(maxAge: 604800) { - ensgID: String - traitCount: Int - studyCount: Int associations: [GwasTargetAssociation] } type GwasTargetAssociation @cacheControl(maxAge: 604800) { + ensgID: String + traitCountForGene: Int + studyCountForGene: Int trait: String efoID: String - studyCount: Int + studyCountForAssoc: Int snpCount: Int wSnpCount: Float geneCountForTrait: Int From 79616e11dc728df6b6f5c562dc93fa3f24de42ea Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Tue, 20 Apr 2021 00:16:32 -0400 Subject: [PATCH 08/13] DRGC resource type makes a good target facet --- src/models/databaseTable.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/models/databaseTable.ts b/src/models/databaseTable.ts index 97981a6..76fef87 100644 --- a/src/models/databaseTable.ts +++ b/src/models/databaseTable.ts @@ -77,7 +77,8 @@ export class DatabaseTable { ["protein-target", ["t2tc"]], ["protein-ncats_idg_list_type", ["ncats_idg_list"]], ["protein-ncats_ligands", ["ncats_ligand_activity", "target", "t2tc"]], - ["protein-ncats_ligand_activity", ["target", "t2tc"]] + ["protein-ncats_ligand_activity", ["target", "t2tc"]], + ["protein-drgc_resource", ["target", "t2tc"]] ]); static getRequiredLinks(table1: string, table2: string): string[] | undefined { From 335c3cfc9e0bcd5626d1b6e556c48aabeb43e33d Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Tue, 20 Apr 2021 09:57:46 -0400 Subject: [PATCH 09/13] flip switch to tcrd 6.10.0 --- src/db_credentials.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db_credentials.js b/src/db_credentials.js index 37a3541..8581424 100644 --- a/src/db_credentials.js +++ b/src/db_credentials.js @@ -3,7 +3,7 @@ // const cred = { DBHOST: 'tcrd.ncats.io', - DBNAME: 'tcrd684', + DBNAME: 'tcrd6100', CONFIGDB: 'pharos_config_prod', USER: 'tcrd', PWORD: '' From 205d514adbb6220fa9b3fb1b1947c24c064bf367 Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Wed, 21 Apr 2021 00:04:41 -0400 Subject: [PATCH 10/13] fixes for tinx stuff, which was broken by new TCRD structure --- src/TCRD.js | 4 ++-- src/models/disease/diseaseList.ts | 2 +- src/resolvers.js | 5 +++-- src/schema.graphql | 3 +-- tests/test12.graphql | 1 - 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/TCRD.js b/src/TCRD.js index 22cc921..2f7d08e 100644 --- a/src/TCRD.js +++ b/src/TCRD.js @@ -1757,7 +1757,7 @@ and b.target_id = ?`, [target.tcrdid])); getTINXForTarget(target, args) { let q = this.db.select(this.db.raw(` -a.*,b.doid, b.score as novelty, a.id as tinxid +a.*, b.doid, b.score as novelty from tinx_importance a, tinx_disease b, t2tc c`)); let sort = true; @@ -1769,7 +1769,7 @@ match(b.name,b.summary) against(? in boolean mode)`, [t])); sort = false; } } - q = q.andWhere(this.db.raw(`a.disease_id = b.id + q = q.andWhere(this.db.raw(`a.doid = b.doid and a.protein_id = c.protein_id and c.target_id = ?`, [target.tcrdid])); diff --git a/src/models/disease/diseaseList.ts b/src/models/disease/diseaseList.ts index b0b20f6..4d106b2 100644 --- a/src/models/disease/diseaseList.ts +++ b/src/models/disease/diseaseList.ts @@ -41,7 +41,7 @@ export class DiseaseList extends DataModelList { importance:knex.raw('(tinx_importance.score)') }) .join(doidList.as('idList'), 'idList.did', 'tinx_disease.doid') - .where(knex.raw('tinx_importance.disease_id = tinx_disease.id')) + .where(knex.raw('tinx_importance.doid = tinx_disease.doid')) .andWhere(knex.raw('tinx_importance.protein_id = t2tc.protein_id')) .andWhere(knex.raw('tinx_importance.protein_id = tinx_novelty.protein_id')) .andWhere(knex.raw('t2tc.target_id = target.id')); diff --git a/src/resolvers.js b/src/resolvers.js index f660ba3..3a952f6 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -1717,9 +1717,10 @@ const resolvers = { TINXDisease: { disease: async function (tinx, _, {dataSources}) { //console.log('~~~~~ tinx: '+tinx.doid); - if (tinx.doid) + if (tinx.doid && dataSources.tcrd.doTree[tinx.doid]) { return dataSources.tcrd.doTree[tinx.doid]; - console.error('No doid in TINX ' + tinx.tinxid); + } + // console.error('No doid in TINX ' + JSON.stringify(tinx)); return null; } } diff --git a/src/schema.graphql b/src/schema.graphql index c744c39..e751aa5 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -372,12 +372,11 @@ type DTO @cacheControl(maxAge: 604800) { } type TINXDisease @cacheControl(maxAge: 604800) { - tinxid: Int! """Disease novelty""" novelty: Float """Importance of disease-target combination""" score: Float - disease: DiseaseOntology! + disease: DiseaseOntology } type TINXTargetDetails @cacheControl(maxAge: 604800) { diff --git a/tests/test12.graphql b/tests/test12.graphql index f3187a7..cac52e2 100644 --- a/tests/test12.graphql +++ b/tests/test12.graphql @@ -27,7 +27,6 @@ } tinxCount tinx(top:50){ - tinxid novelty score disease{ From 335fd4fb2487272a2690f68797f8b75cdef25c4b Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Wed, 21 Apr 2021 01:17:14 -0400 Subject: [PATCH 11/13] fix unit tests --- .../targetQueries/comprehensive.test.js | 4 +- tests/test01.graphql | 48 +++++++++---------- tests/test05.graphql | 43 +++++++++-------- 3 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/__tests__/targetQueries/comprehensive.test.js b/src/__tests__/targetQueries/comprehensive.test.js index a8b6e30..b8021f5 100644 --- a/src/__tests__/targetQueries/comprehensive.test.js +++ b/src/__tests__/targetQueries/comprehensive.test.js @@ -225,8 +225,8 @@ describe('all the queries should be consistent with each other', function () { }); test('Similarity query', () => { - const fullList = new TargetList(tcrd, {top:1000000, filter: {similarity: "(Q6P1J9, GWAS)"}}); - const filteredList = new TargetList(tcrd, {filter: {similarity: "(Q6P1J9, GWAS)", facets: [{facet: "Target Development Level", values: ["Tclin"]}]}}); + const fullList = new TargetList(tcrd, {top:1000000, filter: {similarity: "(DRD2, GWAS)"}}); + const filteredList = new TargetList(tcrd, {filter: {similarity: "(DRD2, GWAS)", facets: [{facet: "Target Development Level", values: ["Tclin"]}]}}); const fullCountQuery = fullList.getCountQuery(); const fullListQuery = fullList.getListQuery(); diff --git a/tests/test01.graphql b/tests/test01.graphql index b33c2d9..696e3de 100644 --- a/tests/test01.graphql +++ b/tests/test01.graphql @@ -201,14 +201,14 @@ diseases { name associationCount + targets { + sym + tdl + novelty + } associations { disassid did - targets { - sym - tdl - novelty - } } } } @@ -220,6 +220,25 @@ diseases(skip: 40) { name associationCount + targetCounts { + name + value + } + targets( + filter: { + facets: [ + { facet: "tdl", values: ["Tclin"] } + { facet: "fam", values: ["Kinase", "Transporter"] } + ] + } + ) { + sym + uniprot + name + tdl + fam + novelty + } associations { type name @@ -228,25 +247,6 @@ drug pvalue source - targetCounts { - name - value - } - targets( - filter: { - facets: [ - { facet: "tdl", values: ["Tclin"] } - { facet: "fam", values: ["Kinase", "Transporter"] } - ] - } - ) { - sym - uniprot - name - tdl - fam - novelty - } } } patentCounts { diff --git a/tests/test05.graphql b/tests/test05.graphql index d068635..f5a1902 100644 --- a/tests/test05.graphql +++ b/tests/test05.graphql @@ -54,13 +54,13 @@ diseases { name associationCount - associations{ - did targets { sym tdl novelty } + associations{ + did } } } @@ -72,6 +72,25 @@ diseases(skip: 40) { name associationCount + targetCounts { + name + value + } + targets( + filter: { + facets: [ + { facet: "tdl", values: ["Tclin"] } + { facet: "fam", values: ["Kinase", "Transporter"] } + ] + } + ) { + sym + uniprot + name + tdl + fam + novelty + } associations { type did @@ -80,25 +99,7 @@ drug pvalue source - targetCounts { - name - value - } - targets( - filter: { - facets: [ - { facet: "tdl", values: ["Tclin"] } - { facet: "fam", values: ["Kinase", "Transporter"] } - ] - } - ) { - sym - uniprot - name - tdl - fam - novelty - } + } } patentCounts { From c399b0470782224c300e0ff29ac1d60ec346f95f Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Fri, 23 Apr 2021 00:45:27 -0400 Subject: [PATCH 12/13] return preferred terms and UNIIs --- src/resolvers.js | 16 +++++++++++----- src/schema.graphql | 7 +++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/resolvers.js b/src/resolvers.js index 3a952f6..c685cd1 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -1362,11 +1362,11 @@ const resolvers = { .select({name: 'name'}) .where('id', gwasData.ncats_disease_id); return query.then(rows => { - if (rows.length > 0) { - return rows[0].name; - } - return null; - }); + if (rows.length > 0) { + return rows[0].name; + } + return null; + }); } return null; } @@ -1700,6 +1700,12 @@ const resolvers = { } return parser(ligand); + }, + preferred_terms: async function (ligand, args, {dataSources}) { + return dataSources.tcrd.db({ncats_ligand_map: 'ncats_ligand_map', ncats_ligands: 'ncats_ligands'}) + .select({term: 'ncats_ligand_map.pt', unii: 'ncats_ligand_map.unii', cas: 'ncats_ligand_map.cas'}) + .where('ncats_ligand_map.ncats_ligand_id', dataSources.tcrd.db.raw('ncats_ligands.id')) + .andWhere('ncats_ligands.identifier', ligand.ligid); } }, diff --git a/src/schema.graphql b/src/schema.graphql index e751aa5..2e7c0d4 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -341,6 +341,13 @@ type Ligand @cacheControl(maxAge: 604800) { """Activity count""" actcnt: Int activities (all: Boolean = true): [LigandActivity] + preferred_terms: [ResolverResult] +} + +type ResolverResult @cacheControl(maxAge: 604800) { + term: String + unii: String + cas: String } type LigandActivity @cacheControl(maxAge: 604800) { From db2d35c8db65767f772dccf618b53f926a8515db Mon Sep 17 00:00:00 2001 From: Keith Kelleher Date: Fri, 23 Apr 2021 23:25:26 -0400 Subject: [PATCH 13/13] return preferred terms and UNIIs flip switch to use TCRD 6.11.0 --- src/db_credentials.js | 6 +++--- src/resolvers.js | 14 ++++---------- src/schema.graphql | 7 ------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/db_credentials.js b/src/db_credentials.js index 8581424..633c63c 100644 --- a/src/db_credentials.js +++ b/src/db_credentials.js @@ -3,9 +3,9 @@ // const cred = { DBHOST: 'tcrd.ncats.io', - DBNAME: 'tcrd6100', - CONFIGDB: 'pharos_config_prod', + DBNAME: 'tcrd6110', USER: 'tcrd', - PWORD: '' + PWORD: '', + CONFIGDB: 'pharos_config_prod', }; module.exports.cred = cred; diff --git a/src/resolvers.js b/src/resolvers.js index c685cd1..e96083d 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -1680,7 +1680,7 @@ const resolvers = { synonyms: async function (ligand, args, {dataSources}) { const parser = function (row) { let synonyms = []; - for (let field of ['PubChem', 'Guide to Pharmacology', 'ChEMBL', 'DrugCentral']) { + for (let field of ['unii', 'PubChem', 'Guide to Pharmacology', 'ChEMBL', 'DrugCentral', 'pt']) { if (row[field]) { synonyms.push({name: field, value: row[field]}); } @@ -1690,23 +1690,17 @@ const resolvers = { }; let synonyms = []; - if (!ligand['PubChem'] && !ligand['Guide to Pharmacology'] && !ligand['ChEMBL'] && !ligand['DrugCentral']) { + if (!ligand['PubChem'] && !ligand['Guide to Pharmacology'] && !ligand['ChEMBL'] && !ligand['DrugCentral'] && !ligand['unii'] && !ligand['pt']) { let query = dataSources.tcrd.db('ncats_ligands') - .select(['PubChem', 'Guide to Pharmacology', 'ChEMBL', 'DrugCentral']) + .select(['unii', 'PubChem', 'Guide to Pharmacology', 'ChEMBL', 'DrugCentral', 'pt']) .where('identifier', ligand.ligid); return query.then(rows => { return parser(rows[0]); - }) + }); } return parser(ligand); }, - preferred_terms: async function (ligand, args, {dataSources}) { - return dataSources.tcrd.db({ncats_ligand_map: 'ncats_ligand_map', ncats_ligands: 'ncats_ligands'}) - .select({term: 'ncats_ligand_map.pt', unii: 'ncats_ligand_map.unii', cas: 'ncats_ligand_map.cas'}) - .where('ncats_ligand_map.ncats_ligand_id', dataSources.tcrd.db.raw('ncats_ligands.id')) - .andWhere('ncats_ligands.identifier', ligand.ligid); - } }, LigandActivity: { diff --git a/src/schema.graphql b/src/schema.graphql index 2e7c0d4..e751aa5 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -341,13 +341,6 @@ type Ligand @cacheControl(maxAge: 604800) { """Activity count""" actcnt: Int activities (all: Boolean = true): [LigandActivity] - preferred_terms: [ResolverResult] -} - -type ResolverResult @cacheControl(maxAge: 604800) { - term: String - unii: String - cas: String } type LigandActivity @cacheControl(maxAge: 604800) {