Skip to content
Draft
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
136 changes: 76 additions & 60 deletions app/models/Backend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ import esecuele.*

import javax.inject.Inject
import models.Helpers.*
import models.db.{IntervalsQuery, QAOTF, QLITAGG, QW2V, TargetsQuery}
import models.db.{
AllByIdInColumnQuery,
ClinicalReportQuery,
IntervalsQuery,
QAOTF,
QLITAGG,
QW2V,
TargetsQuery
}
import models.entities.Publication.*
import models.entities.Associations.*
import models.entities.Biosample.*
Expand Down Expand Up @@ -640,53 +648,6 @@ class Backend @Inject() (implicit
prioritisationFt.flatMap(identity)
}

def getKnownDrugs(
queryString: String,
kv: Map[String, String],
sizeLimit: Option[Int],
cursor: Option[String]
): Future[Option[KnownDrugs]] = {

val pag = Pagination(0, sizeLimit.getOrElse(Pagination.sizeDefault))
val sortByField = sort.FieldSort(field = "phase").desc()
val cbIndex = getIndexOrDefault("known_drugs")

val mappedValues =
Seq(keyValue("index", cbIndex)) ++ kv.map(pair => keyValue(pair._1, pair._2)).toSeq

logger.debug(s"querying known drugs", mappedValues*)

val aggs = Seq(
cardinalityAgg("uniqueTargets", "targetId.raw"),
cardinalityAgg("uniqueDiseases", "diseaseId.raw"),
cardinalityAgg("uniqueDrugs", "drugId.raw"),
valueCountAgg("rowsCount", "drugId.raw")
)

esRetriever
.getByFreeQuery(
cbIndex,
queryString,
kv,
pag,
fromJsValue[KnownDrug],
aggs,
Some(sortByField),
Seq("ancestors", "descendants"),
cursor
)
.map {
case (Seq(), _, _) => Some(KnownDrugs(0, 0, 0, 0, cursor, Seq()))
case (seq, agg, nextCursor) =>
logger.trace(Json.prettyPrint(agg))
val drugs = (agg \ "uniqueDrugs" \ "value").as[Long]
val diseases = (agg \ "uniqueDiseases" \ "value").as[Long]
val targets = (agg \ "uniqueTargets" \ "value").as[Long]
val rowsCount = (agg \ "rowsCount" \ "value").as[Long]
Some(KnownDrugs(drugs, diseases, targets, rowsCount, nextCursor, seq))
}
}

def getEvidencesByVariantId(
datasourceIds: Option[Seq[String]],
variantId: String,
Expand Down Expand Up @@ -792,6 +753,71 @@ class Backend @Inject() (implicit
.map(_.mappedHits)
}

def getClinicalTargetsByTarget(id: String): Future[ClinicalTargets] =
val tableName = getTableWithPrefixOrDefault(defaultOTSettings.clickhouse.clinicalTarget.name)

val clinicalTargetQuery = AllByIdInColumnQuery(id, tableName, 0, Pagination.sizeMax, "targetId")

logger.info(s"getting clinical target with id $id", keyValue("table", tableName))

dbRetriever
.executeQuery[ClinicalTarget, Query](clinicalTargetQuery.query)
.map {
case Seq() =>
logger.info(s"no clinical target found for $id", keyValue("table", tableName))
ClinicalTargets(0, IndexedSeq())
case ct =>
logger.info(s"clinical target found for $id ${ct.length}", keyValue("table", tableName))
ClinicalTargets(ct.length, ct)
}

def getClinicalIndicationsByDrug(id: String): Future[ClinicalIndications] =
val tableName = getTableWithPrefixOrDefault(
defaultOTSettings.clickhouse.clinicalIndication.drugTable.name
)

logger.info(s"getting clinical indications by the drug $id", keyValue("table", tableName))
getClinicalIndications(id, tableName, "drugId")

def getClinicalIndicationsByDisease(id: String): Future[ClinicalIndications] =
val tableName = getTableWithPrefixOrDefault(
defaultOTSettings.clickhouse.clinicalIndication.diseaseTable.name
)

logger.info(s"getting clinical indications by the disease $id", keyValue("table", tableName))
getClinicalIndications(id, tableName, "diseaseId")

def getClinicalReports(ids: Seq[String]): Future[IndexedSeq[ClinicalReport]] = {
val tableName = getTableWithPrefixOrDefault(defaultOTSettings.clickhouse.clinicalReport.name)

val clinicalReportQuery = ClinicalReportQuery(ids, tableName, 0, Pagination.sizeMax)

logger.info(s"getting clinical reports with ids $ids", keyValue("table", tableName))

dbRetriever
.executeQuery[ClinicalReport, Query](clinicalReportQuery.query)
}

private def getClinicalIndications(id: String,
tableName: String,
columnName: String
): Future[ClinicalIndications] = {

val clinicalIndicationsQuery =
AllByIdInColumnQuery(id, tableName, 0, Pagination.sizeMax, columnName)

dbRetriever
.executeQuery[ClinicalIndication, Query](clinicalIndicationsQuery.query)
.map {
case Seq() =>
logger.info(s"no clinical indication found for $id in table $tableName")
ClinicalIndications(0, IndexedSeq())
case cis =>
logger.info(s"clinical indications found for $id in table $tableName: ${cis.length}")
ClinicalIndications(cis.length, cis)
}
}

def getPharmacogenomicsByDrug(id: String): Future[IndexedSeq[Pharmacogenomics]] = {
val queryTerm: Map[String, String] = Map("drugs.drugId.keyword" -> id)
getPharmacogenomics(id, queryTerm)
Expand Down Expand Up @@ -908,7 +934,7 @@ class Backend @Inject() (implicit
def getDrugs(ids: Seq[String]): Future[IndexedSeq[Drug]] = {
val drugIndexName = getIndexOrDefault("drug")

logger.debug(s"querying drugs", keyValue("drug_ids", ids), keyValue("index", drugIndexName))
logger.debug(s"querying drugs with ids: $ids", keyValue("index", drugIndexName))

val queryTerm = Map("id.keyword" -> ids)
esRetriever
Expand All @@ -931,16 +957,6 @@ class Backend @Inject() (implicit
mechanismsOfActionRaw.map(i => Drug.mechanismOfActionRaw2MechanismOfAction(i.mappedHits))
}

def getIndications(ids: Seq[String]): Future[IndexedSeq[Indications]] = {
val index = getIndexOrDefault("drugIndications")
logger.debug(s"querying indications", keyValue("ids", ids), keyValue("index", index))
val queryTerm = Map("id.keyword" -> ids)

esRetriever
.getByIndexedQueryShould(index, queryTerm, Pagination.mkDefault, fromJsValue[Indications])
.map(_.mappedHits)
}

def getDrugWarnings(id: String): Future[IndexedSeq[DrugWarning]] = {
val indexName = getIndexOrDefault("drugWarnings")
logger.debug(s"querying drug warnings", keyValue("id", id), keyValue("index", indexName))
Expand Down Expand Up @@ -968,7 +984,7 @@ class Backend @Inject() (implicit
def getDiseases(ids: Seq[String]): Future[IndexedSeq[Disease]] = {
val diseaseIndexName = getIndexOrDefault("disease")

logger.debug(s"querying diseases", keyValue("ids", ids), keyValue("index", diseaseIndexName))
logger.debug(s"querying diseases with ids: $ids", keyValue("index", diseaseIndexName))

esRetriever.getByIds(diseaseIndexName, ids, fromJsValue[Disease])
}
Expand Down
2 changes: 1 addition & 1 deletion app/models/ClickhouseRetriever.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class ClickhouseRetriever(config: OTSettings)(implicit
case Failure(ex) =>
val qStr = qq.statements.mkString("\n")
logger.error(s"executeQuery an exception was thrown ${ex.getMessage} with Query $qStr")
Vector.empty
Vector.empty // TODO: maybe we should return the error instead of an empty vector, to inform the user
}
}
}
15 changes: 15 additions & 0 deletions app/models/GQLSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,21 @@ object GQLSchema {
)
ctx.ctx.getCredibleSets(credSetQueryArgs, ctx.arg(pageArg))
}
),
Field(
"clinicalReport",
OptionType(clinicalReportImp),
description = Some(""),
arguments = clinicalReportId :: Nil,
resolve = ctx => clinicalReportFetcher.deferOpt(ctx.arg(clinicalReportId))
),
Field(
"clinicalReports",
ListType(clinicalReportImp),
description = Some(""),
arguments = clinicalReportIds :: Nil,
complexity = Some(complexityCalculator(clinicalReportIds)),
resolve = ctx => clinicalReportFetcher.deferSeqOpt(ctx.arg(clinicalReportIds))
)
)
)
Expand Down
29 changes: 29 additions & 0 deletions app/models/db/AllByIdInColumnQuery.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package models.db

import esecuele.Column.{column, literal}
import esecuele.{Column, Format, From, Functions, Limit, OrderBy, PreWhere, Query, Select, Settings}
import utils.OTLogging

case class AllByIdInColumnQuery(id: String,
tableName: String,
offset: Int,
size: Int,
columnName: String
) extends Queryable
with OTLogging {

override val query: Query =
Query(
Select(
Column.star :: Nil
),
From(column(tableName)),
PreWhere(
Functions.in(column(columnName), literal(id))
),
OrderBy(column("id") :: Nil),
Limit(offset, size),
Format("JSONEachRow"),
Settings(Map("output_format_json_escape_forward_slashes" -> "0"))
)
}
39 changes: 39 additions & 0 deletions app/models/db/ClinicalReportQuery.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package models.db

import esecuele.Column.{column, literal}
import esecuele.{
Column,
Format,
From,
Functions,
Limit,
OrderBy,
PreWhere,
Query,
Select,
Settings,
Where
}
import utils.OTLogging

case class ClinicalReportQuery(ids: Seq[String], tableName: String, offset: Int, size: Int)
extends Queryable
with OTLogging {

private val conditional = Where(
Functions.in(column("id"), Functions.set(ids.map(literal).toSeq))
)

override val query: Query =
Query(
Select(
Column.star :: Nil
),
From(column(tableName)),
conditional,
OrderBy(column("id") :: Nil),
Limit(offset, size),
Format("JSONEachRow"),
Settings(Map("output_format_json_escape_forward_slashes" -> "0"))
)
}
3 changes: 3 additions & 0 deletions app/models/entities/ClinicalDiseaseListItem.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package models.entities

case class ClinicalDiseaseListItem(diseaseFromSource: String, diseaseId: String)
21 changes: 21 additions & 0 deletions app/models/entities/ClinicalIndication.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package models.entities

import play.api.libs.json.{Json, OFormat}
import slick.jdbc.GetResult
import utils.OTLogging

case class ClinicalIndication(
id: String,
drugId: Option[String],
diseaseId: Option[String],
maxClinicalStage: String,
clinicalReportIds: Seq[String]
)

object ClinicalIndication extends OTLogging {

implicit val getClinicalIndicationsFromDB: GetResult[ClinicalIndication] =
GetResult(r => Json.parse(r.<<[String]).as[ClinicalIndication])

implicit val clinicalIndicationsF: OFormat[ClinicalIndication] = Json.format[ClinicalIndication]
}
48 changes: 48 additions & 0 deletions app/models/entities/ClinicalIndications.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package models.entities

import models.Backend
import models.gql.Objects.{clinicalIndicationFromDiseaseImp, clinicalIndicationFromDrugImp}
import sangria.schema.{Field, ListType, LongType, ObjectType, fields}

case class ClinicalIndications(
count: Long,
rows: IndexedSeq[ClinicalIndication]
)

object ClinicalIndications {
def empty: ClinicalIndications = ClinicalIndications(0, IndexedSeq.empty)
val clinicalIndicationsFromDrugImp: ObjectType[Backend, ClinicalIndications] = ObjectType(
"clinicalIndicationsFromDrugImp",
"",
fields[Backend, ClinicalIndications](
Field("count",
LongType,
description = Some("Total number of indications results matching the query filters"),
resolve = _.value.count
),
Field(
"rows",
ListType(clinicalIndicationFromDrugImp),
description = Some("List of clinical indications results between drug-disease pairs"),
resolve = _.value.rows
)
)
)
val clinicalIndicationsFromDiseaseImp: ObjectType[Backend, ClinicalIndications] = ObjectType(
"clinicalIndicationsFromDiseaseImp",
"",
fields[Backend, ClinicalIndications](
Field("count",
LongType,
description = Some("Total number of indications results matching the query filters"),
resolve = _.value.count
),
Field(
"rows",
ListType(clinicalIndicationFromDiseaseImp),
description = Some("List of clinical indications results between drug-disease pairs"),
resolve = _.value.rows
)
)
)
}
Loading