Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/client/features/interactions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Interactions extends React.Component {
: source.replace(/\//g,' ')
);
Promise.all(geneIds).then(geneIds=>{
ServerAPI.geneQuery({genes:geneIds.join(' '),target: 'NCBIGENE'}).then(result=>{
ServerAPI.geneQuery({genes:geneIds,target: 'NCBIGENE'}).then(result=>{
const ncbiIds=result.geneInfo.map(gene=> gene.convertedAlias);
ServerAPI.getGeneInformation(ncbiIds).then(result=>{
const geneResults=result.result;
Expand Down
150 changes: 87 additions & 63 deletions src/client/features/search/landing-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { ServerAPI } = require('../../services');
const databases = require('../../common/config').databases;
const Loader = require('react-loader');
const _ = require('lodash');

//usedDatabases=[['Uniprot lookup name',{configName:,gProfiler:}]]
const usedDatabases=new Map ([
['GeneCards',{configName:'Gene Cards',gProfiler:'HGNCSYMBOL',displayName:'Gene Cards'}],
Expand All @@ -14,7 +15,13 @@ const usedDatabases=new Map ([
['Uniprot',{configName:'Uniprot',gProfiler:'Uniprot',displayName:'Uniprot'}]
]);

const linkBuilder= (source,geneQuery)=>{
/**
* Get database link and display name based on gene ids
* @param {string} source Database name
* @param {JSON} geneQuery User input string and matching gene id.
* @return {string: {string: string}} e.g.{MDM2: {Uiprot: Q00978}}
*/
const idFormatter= (source,geneQuery)=>{
let genes={};
const geneArray=geneQuery.geneInfo;
genes.unrecognized=geneQuery.unrecognized;
Expand All @@ -28,27 +35,16 @@ const linkBuilder= (source,geneQuery)=>{
return genes;
};

const pcFallback = (unrecognized,genes) => {
return unrecognized.map(entry=>{
if(!genes[entry]){
return ServerAPI.pcQuery('search', {q:entry,type:'entityreference'}).then((search)=>{
const ids = _.compact(search.searchHit.map(hit=>{
hit =_.reverse(hit.uri.split('/'));
return hit[1]==='uniprot' ? hit[0] : false;
}));
const duplicateCheck = _.compact(ids.map(id=>_.findKey(genes,{'Uniprot':id})));
if(!_.isEmpty(ids) && _.isEmpty(duplicateCheck)){
genes[entry]={'Uniprot': ids[0]};
}
});
}
});
};

/**
* Get database link and display name based on gene ids
* @param {{string:string}} ids NCBI id to search, e.g.{GENE CARD:MDM2}
* @return {[{string:string,string,string}]} Array of database containing link and display name, e.g.{link: URI, displayName: MDM2}
*/
const idToLinkConverter = (ids) =>{
const dbSet = databases.filter(databaseValue => ids[databaseValue.database]);
let dbs = _.assign({},
...dbSet.map(database=>({[database.database]:database.url+database.search+ids[database.database].replace(/[^a-zA-Z0-9:]/g)}))
let dbs = _.assign({}, ...dbSet.map(database=>({
[database.database]: database.url+database.search+ids[database.database].replace(/[^a-zA-Z0-9:]/g)
}))
);

let links = [];
Expand All @@ -61,6 +57,12 @@ const idToLinkConverter = (ids) =>{
return links;
};

/**
* Get gene information from NCBI
* @param {string:string} ids NCBI id to search, e.g.{4193:MDM2}
* @param {} genes Validated gene id from databse, e.g.{gene:{db1:id,db2:id}}
* @return {json} JSON of gene information.
*/
const getNcbiInfo = (ids,genes) => {
const ncbiIds=_.map(ids,(search,id)=>id);
return ServerAPI.getGeneInformation(ncbiIds).then(result=>{
Expand All @@ -81,7 +83,12 @@ const getNcbiInfo = (ids,genes) => {
});
};

const getUniprotInfo= (ids,genes) => {
/**
* Get gene information from Uniprot
* @param {string:string} ids Uniprot accessions to search, e.g.{4193:MDM2}
* @return {json} JSON of gene information.
*/
const getUniprotInfo= (ids) => {
const uniprotIds=_.map(ids,(search,id)=>id);
return ServerAPI.getUniprotnformation(uniprotIds).then(result=>{
return result.map(gene=>{
Expand All @@ -92,24 +99,19 @@ const getUniprotInfo= (ids,genes) => {
}
});
const hgncSymbol = links['Gene Cards'];
const duplicateCheck = _.findKey(genes,{'Gene Cards':hgncSymbol});
if(!duplicateCheck || genes[duplicateCheck]['Uniprot']===gene.accession){
links=idToLinkConverter(links);
return {
databaseID:gene.accession,
name:gene.gene[0].name.value,
function: gene.comments && gene.comments[0].type==='FUNCTION' ? gene.comments[0].text[0].value:'',
hgncSymbol:hgncSymbol,
showMore:{full:true,function:false,synonyms:false},
links:links
};
}
else{
return;
}
return {
databaseID:gene.accession,
name:gene.gene[0].name.value,
function: gene.comments && gene.comments[0].type==='FUNCTION' ? gene.comments[0].text[0].value:'',
hgncSymbol:hgncSymbol,
showMore:{full:true,function:false,synonyms:false},
links:links
};
});
});
};

/*Gets info for a landing box
input: 'TP53'
output: [{
Expand All @@ -122,37 +124,59 @@ synonyms:"TP53, BCC7, LFS1, P53, TRP53"
}]
*/
const getLandingResult= (query)=> {
const q=query.trim();
let q=query.trim().split(' ');
let ncbiIds={},uniprotIds={},labeledId={};
const genesToSearch = [];
q.forEach ((id)=> {
const splitId=id.split(':');

//Parse the query based on the format
if(/uniprot:\w+$/i.test(id)) {
uniprotIds[splitId[1]]=splitId[1];
} else if(/(ncbi:[0-9]+|hgnc:\w+)$/i.test(id)) {
labeledId[splitId[1]]=splitId[1];
genesToSearch.push(splitId[1]);
} else {
genesToSearch.push(splitId[0]);
}
});

//Get gene IDs from each database
const promises= [];
usedDatabases.forEach((database)=>promises.push(
ServerAPI.geneQuery({genes: q,target: database.gProfiler}).then(result=>linkBuilder(database.configName,result))
ServerAPI.geneQuery({
genes: genesToSearch,
target: database.gProfiler
}).then(result=>idFormatter(database.configName,result))
));
return Promise.all(promises).then(values=>{
let genes=values[0];
_.tail(values).forEach(gene=>_.mergeWith(genes,gene,(objValue, srcValue)=>_.assign(objValue,srcValue)));

return Promise.all(promises).then(databaseResults=>{
let genes={};
databaseResults.forEach(databaseResult=>_.merge(genes,databaseResult)); //Merge the array of result into one json
return genes;
}).then(genes=>{
let ncbiIds={},uniprotIds={};
_.forEach(genes,(gene,search)=>{
if(gene['NCBI Gene']){
ncbiIds[gene['NCBI Gene']]=search;
}
else if(gene['Uniprot']){
uniprotIds[gene['Uniprot']]=search;
}
});
let landingBoxes=[];
if(!_.isEmpty(ncbiIds)){
landingBoxes.push(getNcbiInfo(ncbiIds,genes));
}
if(!_.isEmpty(uniprotIds)){
landingBoxes.push(getUniprotInfo(uniprotIds,genes));
}
return Promise.all(landingBoxes).then(landingBoxes=> {
landingBoxes=_.compact(_.flatten(landingBoxes));
if(landingBoxes.length>1){landingBoxes.forEach(box=>box.showMore.full=false);}
return landingBoxes;
});
}).then(genes=> {
_.forEach(genes,(gene,search)=>{
if(gene['NCBI Gene']){
ncbiIds[gene['NCBI Gene']]=search;
}
else if(gene['Uniprot']){
uniprotIds[gene['Uniprot']]=search;
}
});
let landingBoxes=[];
if(!_.isEmpty(ncbiIds)){
landingBoxes.push(getNcbiInfo(ncbiIds,genes));
}
if(!_.isEmpty(uniprotIds)){
landingBoxes.push(getUniprotInfo(uniprotIds));
}
return Promise.all(landingBoxes).then(landingBoxes=> {
landingBoxes=_.uniqWith(_.flatten(landingBoxes),(arrVal, othVal)=>
_.intersectionWith(_.values(arrVal.links),_.values(othVal.links),_.isEqual).length
);
if(landingBoxes.length>1){landingBoxes.forEach(box=>box.showMore.full=false);}
return landingBoxes;
});
});
};

Expand Down Expand Up @@ -243,7 +267,7 @@ const landingBox = (props) => {
h('div.search-landing-section',{key: 'ids'},[hgncSymbol,otherNames]),
h('div.search-landing-section',{key: 'functions'},[functions]),
h('div.search-landing-section',{key: 'links'},[links]),
interactionsLink(box.databaseID,'View Interactions')
interactionsLink(box.hgncSymbol,'View Interactions')
])
];
});
Expand Down
25 changes: 15 additions & 10 deletions src/client/services/server-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@ const ServerAPI = {
},

querySearch(query){
return fetch(`/pc-client/querySearch?${qs.stringify(query)}`, defaultFetchOpts).then(res => res.json());
const queryClone=_.assign({},query);
if(/(uniprot:\w+|ncbi:[0-9]+|hgnc:\w+)$/.test(queryClone.q)){queryClone.q=queryClone.q.split(':')[1];}
return fetch(`/pc-client/querySearch?${qs.stringify(queryClone)}`, defaultFetchOpts).then(res => res.json());
},

geneQuery(query){
query.genes=query.genes.split(' ');
return fetch('/api/validation', {
method:'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify(query)
}).then(res => res.json()).then(ids=> _.assign(ids,{unrecognized:_.tail(ids.unrecognized)}));//remove padding
if(query.genes.length>=1){
return fetch('/api/validation', {
method:'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify(query)
}).then(res => res.json());
}else{
return Promise.resolve({geneInfo:[],unrecognized:[]});
}
},

getGeneInformation(ids){
Expand Down