Commit 9c2df180 authored by Severine Duvaud's avatar Severine Duvaud
Browse files

Beacon v0.4

parent bcc8bcb5
...@@ -83,27 +83,33 @@ function checkPreconditions(params) { ...@@ -83,27 +83,33 @@ function checkPreconditions(params) {
if (!params.alternateBases) { if (!params.alternateBases) {
return { return {
hasError: true, hasError: true,
msg: "Alternate bases not defined, arrayMap supports DUP or DEL followed by optional length" msg: "Alternate bases not defined, arrayMap supports DUP or DEL"
}; };
} }
// Beacon 0.4 if (!alternateBasesMap[params.alternateBases]) {
// alternate bases: DEL[0-9]* AND DUP[0-9]*
var alternate = params.alternateBases.replace(/\d+/, "");
if (!alternateBasesMap[alternate]) {
return { return {
hasError: true, hasError: true,
msg: "Alternate bases not supported, arrayMap supports DUP or DEL followed by optional length" msg: "Alternate bases not supported, arrayMap supports DUP or DEL"
}; };
} }
if (params.length && !Number(params.length)) { // Do not allow minLength and maxLength to be compliant with 0.3
/*
if (params.minlength && !Number(params.minlength)) {
return { return {
hasError: true, hasError: true,
msg: "Length not a number" msg: "min. length not a number"
}; };
} }
if (params.maxlength && !Number(params.maxlength)) {
return {
hasError: true,
msg: "max length not a number"
};
}*/
//TODO add additional checks //TODO add additional checks
return { return {
...@@ -137,7 +143,19 @@ function checkPreconditions(params) { ...@@ -137,7 +143,19 @@ function checkPreconditions(params) {
function buildMongoQuery(params) { function buildMongoQuery(params) {
var position = parseInt(params.start); var position = parseInt(params.start);
var length = params.alternateBases.replace(/(DUP|DEL)/, "") ? parseInt(params.alternateBases.replace(/(DUP|DEL)/, "")) : 0;
// Do not allow minLength and maxLength to be compliant with 0.3
/*
if(params.alternateBases == 'DEL') {
var minLength = params.minlength ? parseInt(params.minlength) : 0;
var maxLength = params.maxlength ? parseInt(params.maxlength) : 0;
if(!minLength && (maxLength > 0)){
minLength = 1;
}
}*/
var andConditions = []; var andConditions = [];
var orConditions = []; var orConditions = [];
...@@ -152,9 +170,7 @@ function buildMongoQuery(params) { ...@@ -152,9 +170,7 @@ function buildMongoQuery(params) {
} }
} }
// Beacon 0.4 var segType = alternateBasesMap[params.alternateBases]
// alternate bases: DEL[0-9]* AND DUP[0-9]*
var segType = alternateBasesMap[params.alternateBases.replace(/\d+/, "")]
var convertedReference = referenceMap[params.assemblyId || defaultReference]; var convertedReference = referenceMap[params.assemblyId || defaultReference];
var condition = {}; var condition = {};
...@@ -167,14 +183,22 @@ function buildMongoQuery(params) { ...@@ -167,14 +183,22 @@ function buildMongoQuery(params) {
//elem match element //elem match element
var condElemMatch = condition[convertedReference]['$elemMatch']; var condElemMatch = condition[convertedReference]['$elemMatch'];
if (length > 0) {
condElemMatch.SEGSIZE = length; // Do not allow minLength and maxLength to be compliant with 0.3
condElemMatch.SEGSTART = position; /*
} if (minLength > 0) { //There is a minLength
else { if (maxLength > 0) { //There is always a minLenght, if there is a max length specified (see code above)
condElemMatch.SEGSTOP = {$gte: position}; condElemMatch.SEGSIZE = { $gte: minLength,$lte: maxLength } // min. and max lengths
condElemMatch.SEGSTART = {$lte: position}; condElemMatch.SEGSTART = position // exact position
} }else { //If there is no max length specified
condElemMatch.SEGSIZE = { $gte: minLength }; // min. length
condElemMatch.SEGSTART = position; // exact position
}
}else { //If there is a position specific
*/
condElemMatch.SEGSTOP = { $gte: position };
condElemMatch.SEGSTART = { $lte: position };
//}
andConditions.push(condition); andConditions.push(condition);
if (orConditions.length > 0) { if (orConditions.length > 0) {
...@@ -202,6 +226,23 @@ function buildMongoQuery(params) { ...@@ -202,6 +226,23 @@ function buildMongoQuery(params) {
function checkResultAndGetResponse(params, datasets) { function checkResultAndGetResponse(params, datasets) {
// Do not allow minLength and maxLength to be compliant with 0.3
// var length = 0;
/*
if (typeof params.minlength != undefined && params.minlength != null && params.minlength != '')
{
length = parseInt(params.minlength);
if (params.alternateBases == 'DUP') {
responseResource.note = "Length provided but not considered when querying DUP";
}
}
var maxLength = 0;
if (typeof params.maxlength != undefined && params.maxlength != null && params.maxlength != '')
{
maxLength = parseInt(params.maxlength);
}
*/
var responses = []; var responses = [];
// The query returns only datasets for which there is at least one sample with at least one matching SEGMENT... // The query returns only datasets for which there is at least one sample with at least one matching SEGMENT...
...@@ -258,9 +299,7 @@ function checkResultAndGetResponse(params, datasets) { ...@@ -258,9 +299,7 @@ function checkResultAndGetResponse(params, datasets) {
"error": null, "error": null,
}; };
// Beacon 0.4 if (!alternateBasesMap[params.alternateBases]) {
// alternate bases: DEL[0-9]* AND DUP[0-9]*
if (!alternateBasesMap[params.alternateBases.replace(/\d+/,"")]) {
response.note = "Type of variant not supported by arrayMap."; response.note = "Type of variant not supported by arrayMap.";
} }
else { else {
...@@ -275,9 +314,12 @@ function checkResultAndGetResponse(params, datasets) { ...@@ -275,9 +314,12 @@ function checkResultAndGetResponse(params, datasets) {
"start": params.start, "start": params.start,
"assemblyId": params.assemblyId, "assemblyId": params.assemblyId,
"datasetIds": params.datasetIds, "datasetIds": params.datasetIds,
// Beacon 0.4
// alternate bases: DEL[0-9]* AND DUP[0-9]*
"alternateBases": params.alternateBases "alternateBases": params.alternateBases
// Do not allow minLength and maxLength to be compliant with 0.3
/*
"length": length,
"maxlength": maxLength
*/
}; };
// BeaconAlleleResponse // BeaconAlleleResponse
......
var beacon = {};
beacon.info = require('./beacon-info.js').info
beacon.checkResultAndGetResponse = require('./beacon-query.js').checkResultAndGetResponse
beacon.checkPreconditions = require('./beacon-query.js').checkPreconditions
beacon.buildMongoQuery = require('./beacon-query.js').buildMongoQuery
beacon.checkDatasetIdentifier = require('./beacon-dataset.js').checkDatasetIdentifier
beacon.buildMongoDatasetQuery = require('./beacon-dataset.js').buildMongoDatasetQuery
beacon.checkDatasetResultAndGetResponse = require('./beacon-dataset.js').checkDatasetResultAndGetResponse
module.exports = beacon;
\ No newline at end of file
/**
* Created by sduvaud on 26/05/16.
*/
var info = require('./beacon-info.js').info;
// store all the dataset identifiers
var allDatasetIds = [];
info['info']['info']['datasets'].forEach(function(dataset){
allDatasetIds.push(dataset.id);
});
function checkDatasetIdentifier(params) {
if (!params.id) {
return {
hasError: true,
msg: "No identifier specified"
};
}
return {
hasError: false
};
}
function buildMongoDatasetQuery(params)
{
console.log("ID=" + params.id);
var groupCondition = {
$group: {
_id: "$ICDMORPHOLOGYCODE",
sampleCount: {$sum: 1},
name: { $first: "$ICDMORPHOLOGY"}
}
};
if (params.id == 'all') {
return [
groupCondition
];
}
else {
var orConditions = [];
var identifiers = params.id.split(','); // comma separated list of datasets
identifiers.forEach(function (id) {
orConditions.push({ICDMORPHOLOGYCODE: id});
});
return [
{
$match: {
$or: orConditions
}
},
groupCondition
];
}
}
function checkDatasetResultAndGetResponse(params, datasets) {
var matchedIdentifiers = [];
datasets.forEach(function(dataset){
matchedIdentifiers.push(dataset._id);
});
var submittedIdentifiers = allDatasetIds;
if (params.id != 'all') {
submittedIdentifiers = params.id.split(',');
}
if (submittedIdentifiers.length != matchedIdentifiers.length) {
var missingIdentifiers = [];
submittedIdentifiers.forEach(function(submitted) {
var found = false;
matchedIdentifiers.forEach(function(matched) {
if (matched == submitted) {
found = true;
}
}
);
if (!found) {
missingIdentifiers.push(submitted);
}
}
);
missingIdentifiers.forEach(function (missing) {
var json = {
"_id": missing,
"sampleCount": 0,
"name": "Dataset not found"
};
datasets.push(json);
}
);
}
return datasets;
}
module.exports.checkDatasetIdentifier = checkDatasetIdentifier;
module.exports.buildMongoDatasetQuery = buildMongoDatasetQuery;
module.exports.checkDatasetResultAndGetResponse = checkDatasetResultAndGetResponse;
\ No newline at end of file
This diff is collapsed.
var info = require('./beacon-info.js').info;
// store all the dataset identifiers
// not used when a list of datasets is entered
// find a better place for this?
var allDatasetIds = [];
info['info']['info']['datasets'].forEach(function(dataset){
allDatasetIds.push(dataset.id);
});
var referenceMap = {
'GRCh38': 'SEGMENTS_HG38',
'GRCh37': 'SEGMENTS_HG19',
'GRCh36': 'SEGMENTS_HG18'
};
//correspondence to arraymap class
var alternateBasesMap = {
"DEL": -1,
"DUP": 1
};
// By default doe Maximilien takes Reference 37. https://github.com/maximilianh/ucscBeacon/blob/master/help.txt
//TODO Should it be the same as Maximilen? Is it specified by beacon documentaiton?
var defaultReference = 'GRCh38';
function checkPreconditions(params) {
if (!params.referenceName) {
return {
hasError: true,
msg: "reference name is not present"
};
}
var referenceNameInvalid = {
hasError: true,
msg: params.referenceName + " reference name not valid"
};
if (Number(params.referenceName)) {
if (params.referenceName < 1 || params.referenceName > 23) {
return referenceNameInvalid;
}
}
else {
if (params.referenceName.match(/^(X|Y)$/i) == null) {
return referenceNameInvalid;
}
}
if (!params.start) {
return {
hasError: true,
msg: "position not present"
};
}
if (!Number(params.start)) {
return {
hasError: true,
msg: "position not a number"
};
}
if (!params.datasetIds) {
return {
hasError: true,
msg: "No dataset provided"
};
}
if (params.datasetIds != 'all') {
var error = checkDatasetIdentifiers(params.datasetIds, allDatasetIds);
if (error.length > 0) {
return {
hasError: true,
msg: "Incorrect dataset(s): " + error.toString()
};
}
}
if (!params.alternateBases) {
return {
hasError: true,
msg: "Alternate bases not defined, arrayMap supports DUP or DEL followed by optional length"
};
}
// Beacon 0.4
// alternate bases: DEL[0-9]* AND DUP[0-9]*
var alternate = params.alternateBases.replace(/\d+/, "");
if (!alternateBasesMap[alternate]) {
return {
hasError: true,
msg: "Alternate bases not supported, arrayMap supports DUP or DEL followed by optional length"
};
}
if (params.length && !Number(params.length)) {
return {
hasError: true,
msg: "Length not a number"
};
}
//TODO add additional checks
return {
hasError: false
};
}
/*
* Latest version of API v-0.3
*
* BeaconAlleleRequest:
* referenceName
* start
* alternateBases
* assemblyId
* datasetIds
*
* BeaconAlleleResponse
* beaconId
* beaconAlleleRequest
* beacondatasetAlleleResponse[]
* beaconError
*
* BeaconDatasetAlleleResponse
* datasetId
* exists
* beaconError
* note
*
* */
function buildMongoQuery(params) {
var position = parseInt(params.start);
var length = params.alternateBases.replace(/(DUP|DEL)/, "") ? parseInt(params.alternateBases.replace(/(DUP|DEL)/, "")) : 0;
var andConditions = [];
var orConditions = [];
//add constraint on datasets if required
if (params.datasetIds) {
if (params.datasetIds != 'all') {
var identifiers = params.datasetIds.split(','); // comma separated list of datasets
identifiers.forEach(function (id) {
orConditions.push({ICDMORPHOLOGYCODE: id});
});
}
}
// Beacon 0.4
// alternate bases: DEL[0-9]* AND DUP[0-9]*
var segType = alternateBasesMap[params.alternateBases.replace(/\d+/, "")]
var convertedReference = referenceMap[params.assemblyId || defaultReference];
var condition = {};
condition[convertedReference] = {
'$elemMatch': {
'CHRO': params.referenceName,
'SEGTYPE': segType
}
};
//elem match element
var condElemMatch = condition[convertedReference]['$elemMatch'];
if (length > 0) {
condElemMatch.SEGSIZE = length;
condElemMatch.SEGSTART = position;
}
else {
condElemMatch.SEGSTOP = {$gte: position};
condElemMatch.SEGSTART = {$lte: position};
}
andConditions.push(condition);
if (orConditions.length > 0) {
andConditions.push({$or: orConditions});
}
return [
{
"$match": {
"$and": andConditions
}
},
{
"$group": {
_id: "$ICDMORPHOLOGYCODE",
// Number of samples with at least one segment
// Datasets with no sample are not shown
// This is of an issue when the user asks for
// all datasets.
observed : { $sum : 1 }
}
}
];
}
function checkResultAndGetResponse(params, datasets) {
var responses = [];
// The query returns only datasets for which there is at least one sample with at least one matching SEGMENT...
// What should we do with "unmatched" datasets?
// Should we show them, as well with an exists: false?
// what about cases where all the datasets are requested?
if (datasets && datasets.length > 0)
{
// var matchedDatasets = datasets.map(function (s) { return checkResult(params, s)}); // checks to be added!
var matchedDatasets = checkResult(params, datasets);
var response;
if (typeof matchedDatasets == undefined && matchedDatasets == null) {
response = {
"exists": null,
"datasetId": null,
"sampleCount": 0,
"error": {
errorCode: 500,
message: "Internal error, DB returned a value but post check is not valid."
},
"note": null
};
responses.push(response);
}else {
matchedDatasets.forEach(function (dataset) {
if (dataset.observed == 0) {
response = {
"exists": false,
"error": null,
"note": null,
"datasetId": dataset._id,
"sampleCount": 0
};
}else {
response = {
"exists": true,
"error": null,
"note": null,
"datasetId": dataset._id,
"sampleCount": dataset.observed
};
}
responses.push(response);
})
}
}else {
response = {
"exists": false,
"datasetId": null,
"sampleCount": 0,
"error": null,
};
// Beacon 0.4
// alternate bases: DEL[0-9]* AND DUP[0-9]*
if (!alternateBasesMap[params.alternateBases.replace(/\d+/,"")]) {
response.note = "Type of variant not supported by arrayMap.";
}
else {
response.note = "No result from arrayMap.";
}
responses.push(response);
}
var queryResource = {
"referenceName": params.referenceName,
"start": params.start,
"assemblyId": params.assemblyId,
"datasetIds": params.datasetIds,
// Beacon 0.4
// alternate bases: DEL[0-9]* AND DUP[0-9]*
"alternateBases": params.alternateBases
};
// BeaconAlleleResponse
return {
"beaconId": info['info']['info']['id'],
"datasetAlleleResponses": responses,
"alleleRequest": queryResource,
"error": null
};
}