Flatten library docs into its own MongoDB collection
/* | ||
* Copyright (c) 2015 Leiden University Medical Center and contributors | ||
* (see AUTHORS.md file for details). | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package nl.lumc.sasc.sentinel.processors | ||
import scala.collection.mutable.ListBuffer | ||
import scala.util.Random.shuffle | ||
import com.novus.salat._ | ||
import com.novus.salat.global._ | ||
import com.mongodb.casbah.Imports._ | ||
import nl.lumc.sasc.sentinel.{ AccLevel, LibType, SeqQcPhase } | ||
import nl.lumc.sasc.sentinel.db.MongodbConnector | ||
import nl.lumc.sasc.sentinel.models.{ SeqStatsAggr, User } | ||
/** | ||
* Base trait that provides support for querying and aggregating metrics for a pipeline. | ||
*/ | ||
trait OutputProcessor extends MongodbConnector { | ||
// TODO: refactor functions in here ~ we can do with less duplication | ||
/** Name of the pipeline that produces the metrics to query. */ | ||
def pipelineName: String | ||
/** Name of the unit attribute that denotes whether it comes from a paired-end library or not. */ | ||
protected implicit val pairAttrib = "isPaired" | ||
/** MongoDB samples collection name of the pipeline. */ | ||
protected lazy val samplesColl = mongo.db(collectionNames.pipelineSamples(pipelineName)) | ||
/** MongoDB libraries collection name of the pipeline. */ | ||
protected lazy val libsColl = mongo.db(collectionNames.pipelineLibs(pipelineName)) | ||
/** | ||
* Match operation builder for collection aggregations. | ||
* | ||
* @param runs Run IDs to filter in. If empty, no run ID filtering is done. | ||
* @param references Reference IDs to filter in. If empty, no reference ID filtering is done. | ||
* @param annotations Annotation IDs to filter in. If empty, no annotation ID filtering is done. | ||
* @param paired If defined, a boolean denoting whether the unit is paired-end or not. If not defined, both paired-end | ||
* and single-end are included in the match. | ||
* @param withKey Whether to return only the `query` object with the `$match` key or not. | ||
* @return a [[DBObject]] representing the `$match` aggregation operation. | ||
*/ | ||
private[processors] def buildMatchOp(runs: Seq[ObjectId], references: Seq[ObjectId], annotations: Seq[ObjectId], | ||
paired: Option[Boolean] = None, withKey: Boolean = true): DBObject = { | ||
val matchBuffer = new ListBuffer[MongoDBObject]() | ||
if (runs.nonEmpty) | ||
matchBuffer += MongoDBObject("runId" -> MongoDBObject("$in" -> runs)) | ||
if (references.nonEmpty) | ||
matchBuffer += MongoDBObject("referenceId" -> MongoDBObject("$in" -> references)) | ||
if (annotations.nonEmpty) | ||
matchBuffer += MongoDBObject("annotationIds" -> | ||
MongoDBObject("$elemMatch" -> MongoDBObject("$in" -> annotations))) | ||
paired match { | ||
case Some(isPaired) => matchBuffer += MongoDBObject(pairAttrib -> isPaired) | ||
case None => ; | ||
} | ||
val query = | ||
if (matchBuffer.nonEmpty) MongoDBObject("$and" -> matchBuffer.toSeq) | ||
else MongoDBObject.empty | ||
if (withKey) MongoDBObject("$match" -> query) | ||
else query | ||
} | ||
/** Sort operation for unit documents */ | ||
private[processors] val opSortUnit = MongoDBObject("$sort" -> MongoDBObject("creationTimeUtc" -> -1)) | ||
/** Raw string of the map function for mapReduce. */ | ||
private[processors] def mapFunc(metricName: String, | ||
libType: Option[LibType.Value])(implicit pairAttrib: String): JSFunction = { | ||
val isPaired = libType match { | ||
case None => "undefined" // don't check for pairs | ||
case Some(LibType.Paired) => "true" // check for isPaired === true | ||
case Some(LibType.Single) => "false" // check for isPaired === false | ||
case otherwise => throw new NotImplementedError | ||
} | ||
// nestedAttrCheck adapted from http://stackoverflow.com/a/2631521/243058 | ||
< |