diff --git a/app/models/Backend.scala b/app/models/Backend.scala
index 3ff537ac..852e6f71 100644
--- a/app/models/Backend.scala
+++ b/app/models/Backend.scala
@@ -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.*
@@ -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,
@@ -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)
@@ -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
@@ -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))
@@ -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])
}
diff --git a/app/models/ClickhouseRetriever.scala b/app/models/ClickhouseRetriever.scala
index cdccde18..105d0d09 100644
--- a/app/models/ClickhouseRetriever.scala
+++ b/app/models/ClickhouseRetriever.scala
@@ -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
}
}
}
diff --git a/app/models/GQLSchema.scala b/app/models/GQLSchema.scala
index e27cd8bd..54ec762d 100644
--- a/app/models/GQLSchema.scala
+++ b/app/models/GQLSchema.scala
@@ -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))
)
)
)
diff --git a/app/models/db/AllByIdInColumnQuery.scala b/app/models/db/AllByIdInColumnQuery.scala
new file mode 100644
index 00000000..fc73af00
--- /dev/null
+++ b/app/models/db/AllByIdInColumnQuery.scala
@@ -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"))
+ )
+}
diff --git a/app/models/db/ClinicalReportQuery.scala b/app/models/db/ClinicalReportQuery.scala
new file mode 100644
index 00000000..73342930
--- /dev/null
+++ b/app/models/db/ClinicalReportQuery.scala
@@ -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"))
+ )
+}
diff --git a/app/models/entities/ClinicalDiseaseListItem.scala b/app/models/entities/ClinicalDiseaseListItem.scala
new file mode 100644
index 00000000..4d658565
--- /dev/null
+++ b/app/models/entities/ClinicalDiseaseListItem.scala
@@ -0,0 +1,3 @@
+package models.entities
+
+case class ClinicalDiseaseListItem(diseaseFromSource: String, diseaseId: String)
diff --git a/app/models/entities/ClinicalIndication.scala b/app/models/entities/ClinicalIndication.scala
new file mode 100644
index 00000000..3294b366
--- /dev/null
+++ b/app/models/entities/ClinicalIndication.scala
@@ -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]
+}
diff --git a/app/models/entities/ClinicalIndications.scala b/app/models/entities/ClinicalIndications.scala
new file mode 100644
index 00000000..105b9868
--- /dev/null
+++ b/app/models/entities/ClinicalIndications.scala
@@ -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
+ )
+ )
+ )
+}
diff --git a/app/models/entities/ClinicalReport.scala b/app/models/entities/ClinicalReport.scala
new file mode 100644
index 00000000..37970877
--- /dev/null
+++ b/app/models/entities/ClinicalReport.scala
@@ -0,0 +1,62 @@
+package models.entities
+
+import play.api.libs.json.{JsString, JsValue, Json, OFormat, Writes}
+import slick.jdbc.GetResult
+import utils.OTLogging
+
+case class ClinRepDrugListItem(drugFromSource: String, drugId: String)
+
+case class ClinicalReport(
+ id: String,
+ source: String,
+ clinicalStage: String,
+ phaseFromSource: Option[String],
+ `type`: Option[String],
+ title: Option[String],
+ trialStudyType: Option[String],
+ trialDescription: Option[String],
+ trialNumberOfArms: Option[Int],
+ trialStartDate: Option[String],
+ trialLiterature: Seq[String],
+ trialOverallStatus: Option[String],
+ trialWhyStopped: Option[String],
+ trialPrimaryPurpose: Option[String],
+ trialPhase: Option[String],
+ trialStopReasonCategories: Seq[String],
+ diseases: Seq[ClinicalDiseaseListItem],
+ drugs: Seq[ClinRepDrugListItem],
+ hasExpertReview: Boolean,
+ countries: Seq[String],
+ year: Option[Int],
+ sideEffects: Seq[ClinicalDiseaseListItem],
+ trialOfficialTitle: Option[String],
+ url: Option[String]
+)
+
+object ClinicalReport extends OTLogging {
+ implicit val getClinicalReportFromDB: GetResult[ClinicalReport] =
+ GetResult { r =>
+ val raw = r.<<[String]
+ val escaped = raw
+ .replaceAll("""\\([*^<>&\[\]_~])""", "$1")
+ .replace("\\", "\\\\")
+ .replace("\n", "\\n")
+ .replaceAll("""\\(nrt)""", "\\\\$1")
+ val json = Json.parse(escaped)
+ json.as[ClinicalReport]
+ }
+
+ implicit val diseaseListItemW: Writes[ClinicalDiseaseListItem] =
+ Json.writes[ClinicalDiseaseListItem]
+
+ implicit val diseaseListItemF: OFormat[ClinicalDiseaseListItem] =
+ Json.format[ClinicalDiseaseListItem]
+
+ implicit val drugListItemW: Writes[ClinRepDrugListItem] = Json.writes[ClinRepDrugListItem]
+
+ implicit val drugListItemF: OFormat[ClinRepDrugListItem] = Json.format[ClinRepDrugListItem]
+
+ implicit val clinicalReportW: Writes[ClinicalReport] = Json.writes[ClinicalReport]
+
+ implicit val clinicalReportF: OFormat[ClinicalReport] = Json.format[ClinicalReport]
+}
diff --git a/app/models/entities/ClinicalTarget.scala b/app/models/entities/ClinicalTarget.scala
new file mode 100644
index 00000000..f7ef818a
--- /dev/null
+++ b/app/models/entities/ClinicalTarget.scala
@@ -0,0 +1,25 @@
+package models.entities
+
+import play.api.libs.json.{Json, OFormat}
+import slick.jdbc.GetResult
+import utils.OTLogging
+
+case class ClinicalTarget(
+ id: String,
+ drugId: Option[String],
+ targetId: Option[String],
+ diseases: Seq[ClinicalDiseaseListItem],
+ maxClinicalStage: String,
+ clinicalReportIds: Seq[String]
+)
+
+object ClinicalTarget extends OTLogging {
+
+ implicit val getClinicalTargetsFromDB: GetResult[ClinicalTarget] =
+ GetResult(r => Json.parse(r.<<[String]).as[ClinicalTarget])
+
+ implicit val clinicalDiseaseListItemF: OFormat[ClinicalDiseaseListItem] =
+ Json.format[ClinicalDiseaseListItem]
+
+ implicit val clinicalTargetsF: OFormat[ClinicalTarget] = Json.format[ClinicalTarget]
+}
diff --git a/app/models/entities/ClinicalTargets.scala b/app/models/entities/ClinicalTargets.scala
new file mode 100644
index 00000000..fb583607
--- /dev/null
+++ b/app/models/entities/ClinicalTargets.scala
@@ -0,0 +1,32 @@
+package models.entities
+
+import models.Backend
+import models.gql.Objects.clinicalTargetImp
+import sangria.schema.{Field, ListType, LongType, ObjectType, fields}
+
+case class ClinicalTargets(
+ count: Long,
+ rows: IndexedSeq[ClinicalTarget]
+)
+
+object ClinicalTargets {
+ def empty: ClinicalTargets = ClinicalTargets(0, IndexedSeq.empty)
+ val clinicalTargetsImp: ObjectType[Backend, ClinicalTargets] = ObjectType(
+ "clinicalTargets",
+ "",
+ fields[Backend, ClinicalTargets](
+ Field("count",
+ LongType,
+ description =
+ Some("Total number of clinical targets results matching the query filters"),
+ resolve = _.value.count
+ ),
+ Field(
+ "rows",
+ ListType(clinicalTargetImp),
+ description = Some("List of clinical clinical targets results between drug-target pairs"),
+ resolve = _.value.rows
+ )
+ )
+ )
+}
diff --git a/app/models/entities/Configuration.scala b/app/models/entities/Configuration.scala
index 4c3db803..d93e069a 100644
--- a/app/models/entities/Configuration.scala
+++ b/app/models/entities/Configuration.scala
@@ -55,6 +55,10 @@ object Configuration {
case class HarmonicSettings(pExponent: Int, datasources: Seq[DatasourceSettings])
+ case class ClinicalIndicationSettings(drugTable: DbTableSettings, diseaseTable: DbTableSettings)
+
+ case class ClinicalTargetSettings(drugTable: DbTableSettings, targetTable: DbTableSettings)
+
/** ClickHouse settings stores the configuration for the entities it handles. Target Disease and
* Harmonic settings used to compute associations on the fly and LUTs for interaction expansions
*/
@@ -66,7 +70,10 @@ object Configuration {
similarities: DbTableSettings,
harmonic: HarmonicSettings,
literature: DbTableSettings,
- literatureIndex: DbTableSettings
+ literatureIndex: DbTableSettings,
+ clinicalIndication: ClinicalIndicationSettings,
+ clinicalReport: DbTableSettings,
+ clinicalTarget: DbTableSettings
)
/** main Open Targets configuration object. It keeps track of meta, elasticsearch and clickhouse
@@ -150,6 +157,10 @@ object Configuration {
implicit val harmonicSettingsJSONImp: OFormat[HarmonicSettings] = Json.format[HarmonicSettings]
implicit val targetSettingsJSONImp: OFormat[TargetSettings] = Json.format[TargetSettings]
implicit val diseaseSettingsJSONImp: OFormat[DiseaseSettings] = Json.format[DiseaseSettings]
+ implicit val clinicalIndicationSettingsJSONImp: OFormat[ClinicalIndicationSettings] =
+ Json.format[ClinicalIndicationSettings]
+ implicit val clinicalTargetSettingsJSONImp: OFormat[ClinicalTargetSettings] =
+ Json.format[ClinicalTargetSettings]
implicit val clickhouseSettingsJSONImp: OFormat[ClickhouseSettings] =
Json.format[ClickhouseSettings]
diff --git a/app/models/entities/Drug.scala b/app/models/entities/Drug.scala
index 89a9a137..777c51b1 100644
--- a/app/models/entities/Drug.scala
+++ b/app/models/entities/Drug.scala
@@ -21,8 +21,6 @@ case class DrugWarning(
case class Reference(ids: Option[Seq[String]], source: String, urls: Option[Seq[String]])
-case class IndicationReference(ids: Option[Seq[String]], source: String)
-
case class MechanismOfActionRow(
mechanismOfAction: String,
actionType: Option[String],
@@ -31,21 +29,6 @@ case class MechanismOfActionRow(
references: Option[Seq[Reference]]
)
-case class IndicationRow(
- maxPhaseForIndication: Double,
- disease: String,
- references: Option[Seq[IndicationReference]]
-)
-
-case class LinkedIds(count: Int, rows: Seq[String])
-
-case class Indications(
- id: String,
- indications: Seq[IndicationRow],
- indicationCount: Long,
- approvedIndications: Option[Seq[String]]
-)
-
case class MechanismsOfAction(
rows: Seq[MechanismOfActionRow],
uniqueActionTypes: Seq[String],
@@ -70,21 +53,14 @@ case class Drug(
synonyms: Seq[String],
tradeNames: Seq[String],
childChemblIds: Option[Seq[String]], // Gone?
- yearOfFirstApproval: Option[Int],
drugType: String,
- isApproved: Option[Boolean],
crossReferences: Option[Seq[DrugReferences]],
parentId: Option[String],
- maximumClinicalTrialPhase: Option[Double],
- hasBeenWithdrawn: Boolean,
- linkedDiseases: Option[LinkedIds],
- linkedTargets: Option[LinkedIds],
- blackBoxWarning: Boolean,
+ maximumClinicalStage: String,
description: Option[String]
)
object Drug {
- implicit val linkedIdsImpW: OFormat[LinkedIds] = Json.format[models.entities.LinkedIds]
// implicit val drugWarningRefenceImpW = Json.format[models.entities.DrugWarningReference]
implicit val drugWarningsReferenceImpR: Reads[models.entities.DrugWarningReference] = (
(JsPath \ "ref_id").read[String] and
@@ -112,11 +88,6 @@ object Drug {
Json.format[models.entities.MechanismOfActionRow]
implicit val mechanismOfActionImpW: OFormat[MechanismsOfAction] =
Json.format[models.entities.MechanismsOfAction]
- implicit val indicationReferenceImpW: OFormat[IndicationReference] =
- Json.format[models.entities.IndicationReference]
- implicit val indicationRowImpW: OFormat[IndicationRow] =
- Json.format[models.entities.IndicationRow]
- implicit val indicationsImpW: OFormat[Indications] = Json.format[models.entities.Indications]
implicit val mechanismOfActionRaw: OFormat[MechanismOfActionRaw] =
Json.format[models.entities.MechanismOfActionRaw]
diff --git a/app/models/entities/Evidence.scala b/app/models/entities/Evidence.scala
index e70316f7..9725cfa6 100644
--- a/app/models/entities/Evidence.scala
+++ b/app/models/entities/Evidence.scala
@@ -77,7 +77,8 @@ case class Evidence(
log2FoldChangePercentileRank: Option[Long],
biologicalModelAllelicComposition: Option[String],
confidence: Option[String],
- clinicalPhase: Option[Double],
+ clinicalStage: Option[String],
+ clinicalReportId: Option[String],
resourceScore: Option[Double],
variantFunctionalConsequenceId: Option[String],
variantFunctionalConsequenceFromQtlId: Option[String],
@@ -91,7 +92,6 @@ case class Evidence(
datasourceId: String,
datatypeId: String,
oddsRatioConfidenceIntervalUpper: Option[Double],
- clinicalStatus: Option[String],
log2FoldChangeValue: Option[Double],
oddsRatio: Option[Double],
cohortDescription: Option[String],
@@ -115,8 +115,8 @@ case class Evidence(
betaConfidenceIntervalLower: Option[Double],
betaConfidenceIntervalUpper: Option[Double],
studyStartDate: Option[String],
- studyStopReason: Option[String],
- studyStopReasonCategories: Option[Seq[String]],
+ trialWhyStopped: Option[String],
+ trialStopReasonCategories: Option[Seq[String]],
targetFromSource: Option[String],
cellLineBackground: Option[String],
contrast: Option[String],
diff --git a/app/models/entities/KnownDrug.scala b/app/models/entities/KnownDrug.scala
deleted file mode 100644
index d6efd2e0..00000000
--- a/app/models/entities/KnownDrug.scala
+++ /dev/null
@@ -1,75 +0,0 @@
-package models.entities
-
-import play.api.libs.json.*
-import play.api.libs.json.Reads.*
-import play.api.libs.functional.syntax.*
-import utils.OTLogging
-
-import scala.util.matching.Regex
-
-case class URL(url: String, name: String)
-case class KnownDrugReference(source: String, ids: Seq[String], urls: Seq[String])
-
-case class KnownDrug(
- approvedSymbol: String,
- approvedName: String,
- label: String,
- prefName: String,
- drugType: String,
- targetId: String,
- diseaseId: String,
- drugId: String,
- phase: Double,
- mechanismOfAction: String,
- status: Option[String],
- targetClass: Seq[String],
- references: Seq[KnownDrugReference],
- ctIds: Seq[String],
- urls: Seq[URL]
-)
-
-case class KnownDrugs(
- uniqueDrugs: Long,
- uniqueDiseases: Long,
- uniqueTargets: Long,
- count: Long,
- cursor: Option[String],
- rows: Seq[KnownDrug]
-)
-
-object KnownDrug extends OTLogging {
-
- val ctPattern: Regex = "NCT(\\d{8})".r
-
- implicit val KnownDrugReferenceImpJSONF: OFormat[KnownDrugReference] =
- Json.format[KnownDrugReference]
- implicit val URLImpW: OWrites[URL] = Json.writes[URL]
- implicit val URLImpR: Reads[URL] = (
- (__ \ "url").read[String] and
- (__ \ "niceName").read[String]
- )(URL.apply)
-
- // approvedSymbol: String, label: String, prefName: String,
- implicit val knownDrugImpW: OWrites[KnownDrug] = Json.writes[KnownDrug]
- implicit val knownDrugImpR: Reads[KnownDrug] = (
- (__ \ "approvedSymbol").read[String] and
- (__ \ "approvedName").read[String] and
- (__ \ "label").read[String] and
- (__ \ "prefName").read[String] and
- (__ \ "drugType").read[String] and
- (__ \ "targetId").read[String] and
- (__ \ "diseaseId").read[String] and
- (__ \ "drugId").read[String] and
- (__ \ "phase").read[Double] and
- (__ \ "mechanismOfAction").read[String] and
- (__ \ "status").readNullable[String] and
- (__ \ "targetClass").readWithDefault[Seq[String]](Seq.empty) and
- (__ \ "references").readWithDefault[Seq[KnownDrugReference]](Seq.empty) and
- (__ \ "urls")
- .readWithDefault[Seq[Map[String, String]]](Seq.empty)
- .map(s => s.flatMap(m => ctPattern findAllIn m("url"))) and
- (__ \ "urls").read[Seq[URL]]
- )(KnownDrug.apply)
-
- implicit val knownDrugsImpF: OFormat[KnownDrugs] = Json.format[KnownDrugs]
-}
diff --git a/app/models/gql/Arguments.scala b/app/models/gql/Arguments.scala
index dcbd86ab..8d79165a 100644
--- a/app/models/gql/Arguments.scala
+++ b/app/models/gql/Arguments.scala
@@ -113,6 +113,13 @@ object Arguments {
val ensemblId: Argument[String] = Argument("ensemblId", StringType, description = "Ensembl ID")
val ensemblIds: Argument[Seq[String @@ FromInput.CoercedScalaResult]] =
Argument("ensemblIds", ListInputType(StringType), description = "List of Ensembl IDs")
+ val clinicalReportId: Argument[String] =
+ Argument("clinicalReportId", StringType, description = "Clinical Report ID")
+ val clinicalReportIds: Argument[Seq[String @@ FromInput.CoercedScalaResult]] =
+ Argument("clinicalReportsIds",
+ ListInputType(StringType),
+ description = "List of Clinical Report IDs"
+ )
val ensemblIdsOpt: Argument[Option[Seq[String]]] =
Argument("ensemblIds",
OptionInputType(ListInputType(StringType)),
diff --git a/app/models/gql/DeferredResolvers.scala b/app/models/gql/DeferredResolvers.scala
index 6069a238..9fc450d6 100644
--- a/app/models/gql/DeferredResolvers.scala
+++ b/app/models/gql/DeferredResolvers.scala
@@ -196,9 +196,9 @@ object DeferredResolvers extends OTLogging {
Fetchers.expressionFetcher,
Fetchers.otarProjectsFetcher,
Fetchers.soTermsFetcher,
- Fetchers.indicationFetcher,
Fetchers.goFetcher,
Fetchers.variantFetcher,
- Fetchers.studyFetcher
+ Fetchers.studyFetcher,
+ Fetchers.clinicalReportFetcher
)
}
diff --git a/app/models/gql/Fetchers.scala b/app/models/gql/Fetchers.scala
index 854acedb..173555ef 100644
--- a/app/models/gql/Fetchers.scala
+++ b/app/models/gql/Fetchers.scala
@@ -2,13 +2,13 @@ package models.gql
import models.entities.{
Biosample,
+ ClinicalReport,
CredibleSet,
Disease,
Drug,
Expressions,
GeneOntologyTerm,
HPO,
- Indications,
OtarProjects,
Reactome,
SequenceOntologyTerm,
@@ -42,9 +42,10 @@ object Fetchers extends OTLogging {
FetcherConfig.maxBatchSize(entities.Configuration.batchSize).caching(targetsFetcherCache),
fetch = (ctx: Backend, ids: Seq[String]) => ctx.getTargets(ids)
)
- val diseasesFetcherCache = FetcherCache.simple
// disease
+ val diseasesFetcherCache = FetcherCache.simple
+
implicit val diseaseHasId: HasId[Disease, String] = HasId[Disease, String](_.id)
val diseasesFetcher: Fetcher[Backend, Disease, Disease, String] = Fetcher(
config =
@@ -106,12 +107,6 @@ object Fetchers extends OTLogging {
fetch = (ctx: Backend, ids: Seq[String]) => ctx.getDrugs(ids)
)
- implicit val indicationHasId: HasId[Indications, String] = HasId[Indications, String](_.id)
- val indicationFetcher: Fetcher[Backend, Indications, Indications, String] = Fetcher(
- config = FetcherConfig.maxBatchSize(entities.Configuration.batchSize),
- fetch = (ctx: Backend, ids: Seq[String]) => ctx.getIndications(ids)
- )
-
implicit val goFetcherId: HasId[GeneOntologyTerm, String] = HasId[GeneOntologyTerm, String](_.id)
val goFetcherCache = FetcherCache.simple
val goFetcher: Fetcher[Backend, GeneOntologyTerm, GeneOntologyTerm, String] = Fetcher(
@@ -151,6 +146,18 @@ object Fetchers extends OTLogging {
)
}
+ val clinicalReportFetcherCache = FetcherCache.simple
+ val clinicalReportFetcher: Fetcher[Backend, ClinicalReport, ClinicalReport, String] = {
+ implicit val clinicalreportFetcherId: HasId[ClinicalReport, String] =
+ HasId[ClinicalReport, String](js => js.id)
+ Fetcher(
+ config = FetcherConfig
+ .maxBatchSize(entities.Configuration.batchSize)
+ .caching(clinicalReportFetcherCache),
+ fetch = (ctx: Backend, ids: Seq[String]) => ctx.getClinicalReports(ids)
+ )
+ }
+
def resetCache(): Unit = {
logger.info("clearing all GraphQL caches")
val fetchers: List[SimpleFetcherCache] = List(
@@ -166,7 +173,8 @@ object Fetchers extends OTLogging {
reactomeFetcherCache,
expressionFetcherCache,
otarProjectsFetcherCache,
- soTermsFetcherCache
+ soTermsFetcherCache,
+ clinicalReportFetcherCache
)
fetchers.foreach(_.clear())
}
diff --git a/app/models/gql/Objects.scala b/app/models/gql/Objects.scala
index f745b054..6a29f1ac 100644
--- a/app/models/gql/Objects.scala
+++ b/app/models/gql/Objects.scala
@@ -8,10 +8,15 @@ import models.entities.Publications.publicationsImp
import models.entities.Colocalisations.*
import models.entities.*
import models.gql.Arguments.*
-import models.gql.Fetchers.*
+import models.gql.Fetchers.{diseasesFetcher, *}
import models.Helpers.ComplexityCalculator.*
+import models.entities.ClinicalIndications.{
+ clinicalIndicationsFromDiseaseImp,
+ clinicalIndicationsFromDrugImp
+}
+import models.entities.ClinicalTargets.clinicalTargetsImp
import play.api.libs.json.*
-import sangria.macros.derive.{DocumentField, *}
+import sangria.macros.derive.*
import sangria.schema.*
import scala.concurrent.ExecutionContext.Implicits.global
@@ -312,23 +317,6 @@ object Objects extends OTLogging {
case None => Seq.empty
}
),
- Field(
- "knownDrugs",
- OptionType(knownDrugsImp),
- description = Some(
- "Set of clinical precedence for drugs with investigational or approved indications " +
- "targeting this gene product according to their curated mechanism of action"
- ),
- arguments = freeTextQuery :: pageSize :: cursor :: Nil,
- complexity = Some(complexityCalculator(pageSize)),
- resolve = ctx =>
- ctx.ctx.getKnownDrugs(
- ctx.arg(freeTextQuery).getOrElse(""),
- Map("targetId.raw" -> ctx.value.id),
- ctx.arg(pageSize),
- ctx.arg(cursor)
- )
- ),
Field(
"associatedDiseases",
associatedOTFDiseasesImp,
@@ -422,6 +410,13 @@ object Objects extends OTLogging {
arguments = pageArg :: Nil,
complexity = Some(complexityCalculator(pageArg)),
resolve = ctx => ctx.ctx.getProteinCodingCoordinatesByTarget(ctx.value.id, ctx.arg(pageArg))
+ ),
+ Field(
+ "drugAndClinicalCandidates",
+ clinicalTargetsImp,
+ description = Some(""),
+ arguments = Nil,
+ resolve = ctx => ctx.ctx.getClinicalTargetsByTarget(ctx.value.id)
)
)
)
@@ -615,25 +610,6 @@ object Objects extends OTLogging {
case None => Seq.empty
}
),
- Field(
- "knownDrugs",
- OptionType(knownDrugsImp),
- description = Some(
- "Investigational or approved drugs indicated for this disease with curated mechanisms of action"
- ),
- arguments = freeTextQuery :: pageSize :: cursor :: Nil,
- complexity = Some(complexityCalculator(pageSize)),
- resolve = ctx =>
- ctx.ctx.getKnownDrugs(
- ctx.arg(freeTextQuery).getOrElse(""),
- Map(
- "diseaseId.raw" -> ctx.value.id,
- "ancestors.raw" -> ctx.value.id
- ),
- ctx.arg(pageSize),
- ctx.arg(cursor)
- )
- ),
Field(
"associatedTargets",
associatedOTFTargetsImp,
@@ -679,6 +655,15 @@ object Objects extends OTLogging {
),
arguments = Nil,
resolve = ctx => diseasesFetcher.deferSeq(ctx.value.ancestors)
+ ),
+ Field(
+ "drugAndClinicalCandidates",
+ clinicalIndicationsFromDiseaseImp,
+ description = Some(
+ "Clinical indications for this disease as reported by clinical trial records."
+ ),
+ arguments = Nil,
+ resolve = ctx => ctx.ctx.getClinicalIndicationsByDisease(ctx.value.id)
)
)
)
@@ -1238,39 +1223,6 @@ object Objects extends OTLogging {
DocumentField("rows", "List of phenotype annotations for the disease")
)
- // howto doc https://sangria-graphql.org/learn/#macro-based-graphql-type-derivation
- implicit lazy val linkedDiseasesImp: ObjectType[Backend, LinkedIds] =
- deriveObjectType[Backend, LinkedIds](
- ObjectTypeName("LinkedDiseases"),
- ObjectTypeDescription("Diseases linked via indications"),
- DocumentField("count", "Total number of linked diseases"),
- ReplaceField(
- "rows",
- Field(
- "rows",
- ListType(diseaseImp),
- Some("List of linked disease entities"),
- resolve = r => diseasesFetcher.deferSeqOpt(r.value.rows)
- )
- )
- )
-
- implicit lazy val linkedTargetsImp: ObjectType[Backend, LinkedIds] =
- deriveObjectType[Backend, LinkedIds](
- ObjectTypeName("LinkedTargets"),
- ObjectTypeDescription("Targets linked via curated mechanisms of action"),
- DocumentField("count", "Total number of linked targets"),
- ReplaceField(
- "rows",
- Field(
- "rows",
- ListType(targetImp),
- Some("List of linked target entities"),
- resolve = r => targetsFetcher.deferSeqOpt(r.value.rows)
- )
- )
- )
-
implicit lazy val drugReferenceImp: ObjectType[Backend, Reference] =
deriveObjectType[Backend, Reference](
ObjectTypeDescription("Reference information supporting the drug mechanisms of action"),
@@ -1400,13 +1352,6 @@ object Objects extends OTLogging {
)
)
- implicit lazy val indicationReferenceImp: ObjectType[Backend, IndicationReference] =
- deriveObjectType[Backend, IndicationReference](
- ObjectTypeDescription("Reference information for drug indications"),
- DocumentField("ids", "List of reference identifiers (e.g., PubMed IDs)"),
- DocumentField("source", "Source of the reference")
- )
-
implicit lazy val mechanismOfActionRowImp: ObjectType[Backend, MechanismOfActionRow] =
deriveObjectType[Backend, MechanismOfActionRow](
ObjectTypeDescription("Mechanism of action information for a drug"),
@@ -1430,38 +1375,6 @@ object Objects extends OTLogging {
)
)
- implicit lazy val indicationRowImp: ObjectType[Backend, IndicationRow] =
- deriveObjectType[Backend, IndicationRow](
- ObjectTypeDescription(
- "Indication information linking a drug or clinical candidate molecule to a disease"
- ),
- DocumentField(
- "maxPhaseForIndication",
- "Maximum clinical trial phase for this drug-disease indication. [Values: -1: `Unknown`, 0: `Phase 0`, 0.5: `Phase I (Early)`, 1: `Phase I`, 2: `Phase II`, 3: `Phase III`, 4: `Phase IV`]"
- ),
- DocumentField("references", "Reference information supporting the indication"),
- ReplaceField(
- "disease",
- Field(
- "disease",
- diseaseImp,
- description = Some("Potential indication disease entity"),
- resolve = r => diseasesFetcher.defer(r.value.disease)
- )
- )
- )
-
- implicit lazy val indicationsImp: ObjectType[Backend, Indications] =
- deriveObjectType[Backend, Indications](
- ObjectTypeDescription("Collection of indications for a drug or clinical candidate molecule"),
- ExcludeFields("id"),
- RenameField("indications", "rows"),
- RenameField("indicationCount", "count"),
- DocumentField("indications", "List of potential indication entries"),
- DocumentField("indicationCount", "Total number of potential indications"),
- DocumentField("approvedIndications", "List of approved indication identifiers")
- )
-
implicit lazy val resourceScoreImp: ObjectType[Backend, ResourceScore] =
deriveObjectType[Backend, ResourceScore](
ObjectTypeDescription("Score from a specific datasource"),
@@ -1574,20 +1487,14 @@ object Objects extends OTLogging {
DocumentField("name", "Generic name of the drug molecule"),
DocumentField("synonyms", "List of alternative names for the drug"),
DocumentField("tradeNames", "List of brand names for the drug"),
- DocumentField("yearOfFirstApproval", "Year when the drug received regulatory approval"),
DocumentField(
"drugType",
"Classification of the molecule's therapeutic category or chemical class (e.g. Antibody)"
),
DocumentField(
- "maximumClinicalTrialPhase",
- "Highest clinical trial phase reached by the drug or clinical candidate molecule. [Values: -1: `Unknown`, 0: `Phase 0`, 0.5: `Phase I (Early)`, 1: `Phase I`, 2: `Phase II`, 3: `Phase III`, 4: `Phase IV`]"
+ "maximumClinicalStage",
+ "Highest clinical stage reached by the drug or clinical candidate molecule"
),
- DocumentField("isApproved",
- "Flag indicating whether the drug has received regulatory approval"
- ),
- DocumentField("hasBeenWithdrawn", "Flag indicating whether the drug was removed from market"),
- DocumentField("blackBoxWarning", "Flag indicating whether the drug has safety warnings"),
DocumentField("crossReferences",
"Cross-reference information for this molecule from external databases"
),
@@ -1611,14 +1518,6 @@ object Objects extends OTLogging {
)
),
AddFields(
- Field(
- "approvedIndications",
- OptionType(ListType(StringType)),
- description = Some("Indications for which there is a phase IV clinical trial"),
- resolve = r =>
- DeferredValue(indicationFetcher.deferOpt(r.value.id))
- .map(_.flatMap(_.approvedIndications))
- ),
Field(
"drugWarnings",
ListType(drugWarningsImp),
@@ -1674,32 +1573,6 @@ object Objects extends OTLogging {
),
resolve = ctx => ctx.ctx.getMechanismsOfAction(ctx.value.id)
),
- Field(
- "indications",
- OptionType(indicationsImp),
- description = Some(
- "Investigational and approved indications curated from clinical trial records and " +
- "post-marketing package inserts"
- ),
- resolve = ctx => DeferredValue(indicationFetcher.deferOpt(ctx.value.id))
- ),
- Field(
- "knownDrugs",
- OptionType(knownDrugsImp),
- description = Some(
- "Curated Clinical trial records and and post-marketing package inserts " +
- "with a known mechanism of action"
- ),
- arguments = freeTextQuery :: pageSize :: cursor :: Nil,
- complexity = Some(complexityCalculator(pageSize)),
- resolve = ctx =>
- ctx.ctx.getKnownDrugs(
- ctx.arg(freeTextQuery).getOrElse(""),
- Map("drugId.raw" -> ctx.value.id),
- ctx.arg(pageSize),
- ctx.arg(cursor)
- )
- ),
Field(
"adverseEvents",
OptionType(adverseEventsImp),
@@ -1719,33 +1592,181 @@ object Objects extends OTLogging {
arguments = pageArg :: Nil,
complexity = Some(complexityCalculator(pageArg)),
resolve = ctx => ctx.ctx.getPharmacogenomicsByDrug(ctx.value.id)
- )
- ),
- ReplaceField(
- "linkedDiseases",
- Field(
- "linkedDiseases",
- OptionType(linkedDiseasesImp),
- description = Some("List of molecule potential indications"),
- resolve = r => r.value.linkedDiseases
- )
- ),
- ReplaceField(
- "linkedTargets",
+ ),
Field(
- "linkedTargets",
- OptionType(linkedTargetsImp),
- description = Some("List of molecule targets based on molecule mechanism of action"),
- resolve = ctx => {
- val moa: Future[MechanismsOfAction] = ctx.ctx.getMechanismsOfAction(ctx.value.id)
- val targets: Future[Seq[String]] =
- moa.map(m => m.rows.flatMap(r => r.targets.getOrElse(Seq.empty)))
- targets.map(t => LinkedIds(t.size, t))
- }
+ "indications",
+ clinicalIndicationsFromDrugImp,
+ description = Some(
+ "Clinical indications for this drug as reported by clinical trial records."
+ ),
+ arguments = Nil,
+ resolve = ctx => ctx.ctx.getClinicalIndicationsByDrug(ctx.value.id)
)
)
)
+ implicit val clinRepDiseaseListItemImp: ObjectType[Backend, ClinicalDiseaseListItem] =
+ deriveObjectType[Backend, ClinicalDiseaseListItem](
+ ReplaceField(
+ "diseaseId",
+ Field(
+ "disease",
+ OptionType(diseaseImp),
+ description = Some(""),
+ resolve = ctx =>
+ val tId: String = ctx.value.diseaseId
+ logger.debug(s"finding disease $tId")
+
+ tId match {
+ case "" => None
+ case _ => diseasesFetcher.deferOpt(tId)
+ }
+ )
+ )
+ )
+
+ implicit val clinRepDrugListItemImp: ObjectType[Backend, ClinRepDrugListItem] =
+ deriveObjectType[Backend, ClinRepDrugListItem](
+ ReplaceField(
+ "drugId",
+ Field(
+ "drug",
+ OptionType(drugImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val id = ctx.value.drugId
+ logger.debug(s"finding drug $id")
+
+ id match {
+ case "" => None
+ case _ => drugsFetcher.deferOpt(id)
+ }
+ }
+ )
+ )
+ )
+
+ implicit val clinicalReportImp: ObjectType[Backend, ClinicalReport] =
+ deriveObjectType[Backend, ClinicalReport]()
+
+ implicit val clinicalIndicationFromDiseaseImp: ObjectType[Backend, ClinicalIndication] =
+ deriveObjectType[Backend, ClinicalIndication](
+ ObjectTypeName("ClinicalIndicationFromDisease"),
+ ExcludeFields("diseaseId"),
+ ReplaceField(
+ "drugId",
+ Field(
+ "drug",
+ OptionType(drugImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val id: Option[String] = ctx.value.drugId
+ logger.debug(s"finding drug $id")
+
+ id match {
+ case None => None
+ case Some(dId) => drugsFetcher.deferOpt(dId)
+ }
+ }
+ )
+ ),
+ ReplaceField(
+ "clinicalReportIds",
+ Field(
+ "clinicalReports",
+ ListType(clinicalReportImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val ids = ctx.value.clinicalReportIds
+ logger.debug(s"finding clinical reports for ids ${ids.mkString(",")}")
+ clinicalReportFetcher.deferSeqOpt(ids)
+ }
+ )
+ )
+ )
+
+ implicit val clinicalIndicationFromDrugImp: ObjectType[Backend, ClinicalIndication] =
+ deriveObjectType[Backend, ClinicalIndication](
+ ObjectTypeName("ClinicalIndicationFromDrug"),
+ ExcludeFields("drugId"),
+ ReplaceField(
+ "diseaseId",
+ Field(
+ "disease",
+ OptionType(diseaseImp),
+ description = Some(""),
+ resolve = ctx =>
+ ctx.value.diseaseId match {
+ case Some(tId) =>
+ logger.debug(s"finding disease $tId")
+ diseasesFetcher.deferOpt(tId)
+ case None => None
+ }
+ )
+ ),
+ ReplaceField(
+ "clinicalReportIds",
+ Field(
+ "clinicalReports",
+ ListType(clinicalReportImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val ids = ctx.value.clinicalReportIds
+ logger.debug(s"finding clinical reports for ids ${ids.mkString(",")}")
+ clinicalReportFetcher.deferSeqOpt(ids)
+ }
+ )
+ )
+ )
+
+ implicit val clinicalTargetImp: ObjectType[Backend, ClinicalTarget] =
+ deriveObjectType[Backend, ClinicalTarget](
+ ObjectTypeName("ClinicalTargetFromTarget"),
+ ExcludeFields("targetId"),
+ ReplaceField(
+ "drugId",
+ Field(
+ "drug",
+ OptionType(drugImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val id: Option[String] = ctx.value.drugId
+ logger.debug(s"finding drug $id")
+
+ id match {
+ case None => None
+ case Some(dId) => drugsFetcher.deferOpt(dId)
+ }
+ }
+ )
+ ),
+ ReplaceField(
+ "clinicalReportIds",
+ Field(
+ "clinicalReports",
+ ListType(clinicalReportImp),
+ description = Some(
+ ""
+ ),
+ resolve = ctx => {
+ val ids = ctx.value.clinicalReportIds
+ logger.debug(s"finding clinical reports for ids ${ids.mkString(",")}")
+ clinicalReportFetcher.deferSeqOpt(ids)
+ }
+ )
+ )
+ )
+
implicit val datasourceSettingsImp: ObjectType[Backend, DatasourceSettings] =
deriveObjectType[Backend, DatasourceSettings](
ObjectTypeDescription(
@@ -1789,6 +1810,18 @@ object Objects extends OTLogging {
ObjectTypeDescription("Disease-specific database settings configuration"),
DocumentField("associations", "Database table settings for disease associations")
)
+ implicit val clinicalIndicationSettingsImp: ObjectType[Backend, ClinicalIndicationSettings] =
+ deriveObjectType[Backend, ClinicalIndicationSettings](
+ ObjectTypeDescription("Clinical indication database settings configuration"),
+ DocumentField("drugTable", "Database table settings for drug indications"),
+ DocumentField("diseaseTable", "Database table settings for disease indications")
+ )
+ implicit val clinicalTargetSettingsImp: ObjectType[Backend, ClinicalTargetSettings] =
+ deriveObjectType[Backend, ClinicalTargetSettings](
+ ObjectTypeDescription("Clinical indication database settings configuration"),
+ DocumentField("drugTable", "Database table settings for drug indications"),
+ DocumentField("targetTable", "Database table settings for disease indications")
+ )
implicit val harmonicSettingsImp: ObjectType[Backend, HarmonicSettings] =
deriveObjectType[Backend, HarmonicSettings](
ObjectTypeDescription("Harmonic mean scoring settings for association calculations"),
@@ -1805,7 +1838,9 @@ object Objects extends OTLogging {
DocumentField("similarities", "Database table settings for entity similarities"),
DocumentField("harmonic", "Harmonic mean scoring settings"),
DocumentField("literature", "Database table settings for literature data"),
- DocumentField("literatureIndex", "Database table settings for literature index")
+ DocumentField("literatureIndex", "Database table settings for literature index"),
+ DocumentField("clinicalIndication", "Database table settings for clinical indications"),
+ DocumentField("clinicalTarget", "Database table settings for clinical target")
)
implicit val evidenceSourceImp: ObjectType[Backend, EvidenceSource] =
deriveObjectType[Backend, EvidenceSource](
@@ -1870,87 +1905,6 @@ object Objects extends OTLogging {
DocumentField("id", "Gene ontology term identifier [bioregistry:go]"),
DocumentField("name", "Gene ontology term name")
)
- implicit val knownDrugReferenceImp: ObjectType[Backend, KnownDrugReference] =
- deriveObjectType[Backend, KnownDrugReference](
- ObjectTypeDescription("Reference information for known drug indications"),
- DocumentField("source", "Source of the reference (e.g., PubMed, FDA, package inserts)"),
- DocumentField("ids", "List of reference identifiers"),
- DocumentField("urls", "List of URLs linking to the reference")
- )
-
- implicit val URLImp: ObjectType[Backend, URL] = deriveObjectType[Backend, URL](
- ObjectTypeDescription("Source URL for clinical trials, FDA and package inserts"),
- DocumentField("url", "List of web addresses that support the drug/indication pair"),
- DocumentField("name", "List of human readable names for the reference source")
- )
-
- implicit val knownDrugImp: ObjectType[Backend, KnownDrug] = deriveObjectType[Backend, KnownDrug](
- ObjectTypeDescription(
- "For any approved or clinical candidate drug, includes information on the target gene product and indication. It is derived from the ChEMBL target/disease evidence."
- ),
- DocumentField(
- "approvedSymbol",
- "Approved gene symbol of the target modulated by the drug"
- ),
- DocumentField("approvedName",
- "Approved full name of the gene or gene product modulated by the drug"
- ),
- DocumentField("label", "Disease label for the condition being treated"),
- DocumentField("prefName", "Commonly used name for the drug"),
- DocumentField("drugType", "Classification of the modality of the drug (e.g. Small molecule)"),
- DocumentField("targetId", "Open Targets target identifier"),
- DocumentField("diseaseId", "Open Targets disease identifier"),
- DocumentField("drugId", "Open Targets molecule identifier"),
- DocumentField(
- "phase",
- "Clinical development stage of the drug. [Values: -1: `Unknown`, 0: `Phase 0`, 0.5: `Phase I (Early)`, 1: `Phase I`, 2: `Phase II`, 3: `Phase III`, 4: `Phase IV`]"
- ),
- DocumentField("mechanismOfAction", "Drug pharmacological action"),
- DocumentField("status", "Clinical trial status for the drug/indication pair"),
- DocumentField("targetClass",
- "Classification category of the drug's biological target (e.g. Enzyme)"
- ),
- DocumentField("references", "Source urls for FDA or package inserts"),
- DocumentField("ctIds", "Clinicaltrials.gov identifiers on entry trials"),
- DocumentField("urls", "List of web addresses that support the drug/indication pair"),
- AddFields(
- Field(
- "disease",
- OptionType(diseaseImp),
- description = Some("Curated disease indication entity"),
- resolve = r => diseasesFetcher.deferOpt(r.value.diseaseId)
- ),
- Field(
- "target",
- OptionType(targetImp),
- description = Some("Drug target entity based on curated mechanism of action"),
- resolve = r => targetsFetcher.deferOpt(r.value.targetId)
- ),
- Field(
- "drug",
- OptionType(drugImp),
- description = Some("Curated drug entity"),
- resolve = r => drugsFetcher.deferOpt(r.value.drugId)
- )
- )
- )
-
- implicit val knownDrugsImp: ObjectType[Backend, KnownDrugs] =
- deriveObjectType[Backend, KnownDrugs](
- ObjectTypeDescription(
- "Set of clinical precedence for drugs with investigational or " +
- "approved indications targeting gene products according to their curated mechanism of action"
- ),
- DocumentField("uniqueDrugs", "Total unique drug or clinical candidate molecules"),
- DocumentField("uniqueDiseases", "Total unique diseases or phenotypes"),
- DocumentField(
- "uniqueTargets",
- "Total unique known mechanism of action targets"
- ),
- DocumentField("cursor", "Opaque pagination cursor to request the next page of results"),
- DocumentField("count", "Total number of entries"),
- DocumentField("rows", "Clinical precedence entries with known mechanism of action")
- )
lazy val mUnionType: UnionType[Backend] =
UnionType(
@@ -2742,10 +2696,10 @@ object Objects extends OTLogging {
DocumentField("biologicalModelAllelicComposition", "Allelic composition of the model organism"),
DocumentField("confidence", "Confidence qualifier on the reported evidence"),
DocumentField(
- "clinicalPhase",
- "Phase of the clinical trial. [Values: -1: `Unknown`, 0: `Phase 0`, 0.5: `Phase I (Early)`, 1: `Phase I`, 2: `Phase II`, 3: `Phase III`, 4: `Phase IV`]"
+ "clinicalStage",
+ "Clinical stage of the drug-disease pair"
),
- DocumentField("clinicalStatus", "Current stage of a clinical study"),
+ DocumentField("clinicalReportId", "Identifier of the clinical report"),
DocumentField("clinicalSignificances", "Standard terms to define clinical significance"),
DocumentField("resourceScore",
"Score provided by datasource indicating strength of target-disease association"
@@ -2785,10 +2739,8 @@ object Objects extends OTLogging {
DocumentField("betaConfidenceIntervalLower", "Lower value of the confidence interval"),
DocumentField("betaConfidenceIntervalUpper", "Upper value of the confidence interval"),
DocumentField("studyStartDate", "Start date of study in a YYYY-MM-DD format"),
- DocumentField("studyStopReason", "Reason why a study has been stopped"),
- DocumentField("studyStopReasonCategories",
- "Predicted reason(s) why the study has been stopped based on studyStopReason"
- ),
+ DocumentField("trialWhyStopped", "Reason why the trial was stopped, as reported"),
+ DocumentField("trialStopReasonCategories", "Categorised reason(s) why the trial was stopped"),
DocumentField("cellLineBackground", "Background of the derived cell lines"),
DocumentField("contrast", "Experiment contrast"),
DocumentField("crisprScreenLibrary",
diff --git a/conf/application.conf b/conf/application.conf
index bf37bfa8..44c3c21e 100644
--- a/conf/application.conf
+++ b/conf/application.conf
@@ -32,6 +32,24 @@ ot {
label = "Literature index ocurrences table"
name = "literature_index"
}
+ clinicalReport {
+ label = "Clinical report table"
+ name = "clinical_report"
+ }
+ clinicalIndication {
+ drugTable {
+ label = "Clinical indication drug table"
+ name = "clinical_indication_drug"
+ }
+ diseaseTable {
+ label = "Clinical indication disease table"
+ name = "clinical_indication_disease"
+ }
+ }
+ clinicalTarget {
+ label = "Clinical target table"
+ name = "clinical_target"
+ }
similarities {
label = "Similarity table for the Word2Vec model"
name = "ml_w2v"
diff --git a/conf/logback.xml b/conf/logback.xml
index 463b948d..154a98f3 100644
--- a/conf/logback.xml
+++ b/conf/logback.xml
@@ -24,12 +24,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/production.xml b/production.xml
index 38a077fd..a805757e 100644
--- a/production.xml
+++ b/production.xml
@@ -32,13 +32,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/queries.graphql b/queries.graphql
index 75b1e097..625f404f 100644
--- a/queries.graphql
+++ b/queries.graphql
@@ -34,13 +34,6 @@ query test {
}
}
}
- knownDrugs {
- rows {
- drugType
- targetId
- diseaseId
- }
- }
}
search(queryString: "erectile") {
total
@@ -168,12 +161,6 @@ query test {
topCategory
}
}
- knownDrugs {
- uniqueDrugs
- uniqueDiseases
- uniqueTargets
- count
- }
cancerBiomarkers {
uniqueDrugs
uniqueDiseases
@@ -205,16 +192,6 @@ query test {
name
disease
}
- knownDrugs {
- uniqueDrugs
- uniqueDiseases
- uniqueTargets
- count
- rows {
- drugType
- targetId
- }
- }
relatedDiseases {
maxCountAOrB
count
@@ -225,17 +202,8 @@ query test {
name
synonyms
tradeNames
- yearOfFirstApproval
drugType
- maximumClinicalTrialPhase
- hasBeenWithdrawn
- withdrawnNotice {
- classes
- countries
- reasons
- year
- }
- internalCompound
+ maximumClinicalStage
mechanismsOfAction {
uniqueActionTypes
uniqueTargetTypes
@@ -252,7 +220,6 @@ query test {
}
}
}
- blackBoxWarning
indications {
count
rows {
@@ -277,40 +244,5 @@ query test {
criticalValue
}
}
- knownDrugs {
- uniqueDrugs
- uniqueDiseases
- uniqueTargets
- count
- rows {
- drugType
- targetId
- diseaseId
- phase
- mechanismOfAction
- status
- activity
- targetClass
- ctIds
- }
- }
}
- knwonDrugs: target(ensemblId: "ENSG00000105650") {
- approvedSymbol
- knownDrugs(sortField:"label", sortOrder:Asc) {
- count
- rows {
- drugType
- targetId
- diseaseId
- approvedSymbol
- label
- prefName
- mechanismOfAction
- drug {
- synonyms
- }
- }
- }
- }
}
diff --git a/test/controllers/GqlTest.scala b/test/controllers/GqlTest.scala
index 36c17655..77851aa3 100644
--- a/test/controllers/GqlTest.scala
+++ b/test/controllers/GqlTest.scala
@@ -138,7 +138,7 @@ class GqlTest
"return valid response for Bibliography summary fragment" taggedAs (IntegrationTestTag,
ClickhouseTestTag
) in {
- testQueryAgainstGqlEndpoint(DiseaseDrugFragment("Bibliography_BibliographySummaryFragment"))
+ testQueryAgainstGqlEndpoint(DrugFragment("Bibliography_BibliographySummaryFragment"))
}
"return valid response for Bibliography similar entities summary fragment" taggedAs (
IntegrationTestTag,
@@ -330,9 +330,6 @@ class GqlTest
"return a valid response for disease profile header" taggedAs IntegrationTestTag in {
testQueryAgainstGqlEndpoint(DiseaseFragment("DiseasePage_ProfileHeader"))
}
- "return a valid response for known drugs" taggedAs IntegrationTestTag in {
- testQueryAgainstGqlEndpoint(DiseaseDrugFragment("KnownDrugs_KnownDrugsSummaryFragment"))
- }
"return a valid response for ontology summary fragment" taggedAs IntegrationTestTag in {
testQueryAgainstGqlEndpoint(DiseaseFragment("Ontology_OntologySummaryFragment"))
}
@@ -428,12 +425,6 @@ class GqlTest
}
}
- "Known Drugs query" must {
- "return a valid response" taggedAs IntegrationTestTag in {
- testQueryAgainstGqlEndpoint(KnownDrugs("KnownDrugs_KnownDrugsQuery"))
- }
- }
-
"MolecularInteractions" must {
"return a valid response for interaction stats" taggedAs IntegrationTestTag in {
testQueryAgainstGqlEndpoint(Target("MolecularInteractions_InteractionsStats"))
@@ -522,9 +513,6 @@ class GqlTest
"return valid gene ontology response" taggedAs IntegrationTestTag in {
testQueryAgainstGqlEndpoint(TargetFragment("GeneOntology_GeneOntologySummary"))
}
- "return valid known drugs fragment response" taggedAs IntegrationTestTag in {
- testQueryAgainstGqlEndpoint(TargetFragment("KnownDrugs_KnownDrugsSummary"))
- }
"return valid response for molecular interactions" taggedAs IntegrationTestTag in {
testQueryAgainstGqlEndpoint(TargetFragment("MolecularInteractions_InteractionsSummary"))
}
diff --git a/test/inputs/GqlCase.scala b/test/inputs/GqlCase.scala
index 683450b2..99b7fa40 100644
--- a/test/inputs/GqlCase.scala
+++ b/test/inputs/GqlCase.scala
@@ -151,12 +151,6 @@ case class DiseaseFragment(file: String) extends AbstractDisease with GqlFragmen
.replace("xyz", "$efoId")
}
-case class DiseaseDrugFragment(file: String) extends AbstractDisease with GqlFragment[String] {
- def generateFragmentQuery: String =
- s"$fragmentQuery query DiseaseFragment(xyz: String!) { disease(efoId: xyz) { knownDrugs { rows { drug { ...$fragmentName } } } } }"
- .replace("xyz", "$efoId")
-}
-
/*
This is a fragment on disease which takes a gene as an argument. Used on the FE to create
summary information.
@@ -190,19 +184,6 @@ case class GeneOntology(file: String) extends GqlCase[List[String]] {
"""
}
-case class KnownDrugs(file: String) extends GqlCase[String] {
- val inputGenerator = geneGenerator
-
- def generateVariables(target: String) =
- s"""
- "variables": {
- "ensgId": "$target",
- "cursor": null,
- "freeTextQuery": null
- }
- """
-}
-
case class Search(file: String) extends GqlCase[String] {
override val inputGenerator = searchGenerator
diff --git a/test/resources/gqlQueries/APIPage_DrugAnnotation.gql b/test/resources/gqlQueries/APIPage_DrugAnnotation.gql
index 38a4c675..385c8249 100644
--- a/test/resources/gqlQueries/APIPage_DrugAnnotation.gql
+++ b/test/resources/gqlQueries/APIPage_DrugAnnotation.gql
@@ -2,9 +2,6 @@ query drugApprovalWithdrawnWarningData {
drug(chemblId: "CHEMBL118") {
name
id
- isApproved
- hasBeenWithdrawn
- blackBoxWarning
drugWarnings {
warningType
description
diff --git a/test/resources/gqlQueries/Chembl_ChemblQuery.gql b/test/resources/gqlQueries/Chembl_ChemblQuery.gql
index d9c86369..99be3c46 100644
--- a/test/resources/gqlQueries/Chembl_ChemblQuery.gql
+++ b/test/resources/gqlQueries/Chembl_ChemblQuery.gql
@@ -4,7 +4,7 @@ query ChemblQuery($ensemblId: String!, $efoId: String!, $size: Int!, $cursor: St
chembl: evidences(
ensemblIds: [$ensemblId]
enableIndirect: true
- datasourceIds: ["chembl"]
+ datasourceIds: ["clinical_precedence"]
size: $size
cursor: $cursor
) {
@@ -36,16 +36,11 @@ query ChemblQuery($ensemblId: String!, $efoId: String!, $size: Int!, $cursor: St
variantEffect
directionOnTrait
targetFromSourceId
- clinicalPhase
- clinicalStatus
+ clinicalStage
+ clinicalReportId
studyStartDate
- studyStopReason
- studyStopReasonCategories
- cohortPhenotypes
- urls {
- niceName
- url
- }
+ trialWhyStopped
+ trialStopReasonCategories
}
}
}
diff --git a/test/resources/gqlQueries/Chembl_ChemblSummaryFragment.gql b/test/resources/gqlQueries/Chembl_ChemblSummaryFragment.gql
index e0a749db..481f8060 100644
--- a/test/resources/gqlQueries/Chembl_ChemblSummaryFragment.gql
+++ b/test/resources/gqlQueries/Chembl_ChemblSummaryFragment.gql
@@ -2,7 +2,7 @@ fragment ChemblSummaryFragment on Disease {
chembl: evidences(
ensemblIds: [$ensgId]
enableIndirect: true
- datasourceIds: ["chembl"]
+ datasourceIds: ["clinical_precedence"]
size: 0
) {
count
diff --git a/test/resources/gqlQueries/DrugPage_ProfileHeader.gql b/test/resources/gqlQueries/DrugPage_ProfileHeader.gql
index d17bab3c..f5cb3f04 100644
--- a/test/resources/gqlQueries/DrugPage_ProfileHeader.gql
+++ b/test/resources/gqlQueries/DrugPage_ProfileHeader.gql
@@ -10,10 +10,7 @@ fragment DrugProfileHeaderFragment on Drug {
id
name
}
- isApproved
- hasBeenWithdrawn
- blackBoxWarning
- maximumClinicalTrialPhase
+ maximumClinicalStage
tradeNames
yearOfFirstApproval
}
diff --git a/test/resources/gqlQueries/DrugWarnings_DrugWarningsQuery.gql b/test/resources/gqlQueries/DrugWarnings_DrugWarningsQuery.gql
index 2f282f0f..ab19b599 100644
--- a/test/resources/gqlQueries/DrugWarnings_DrugWarningsQuery.gql
+++ b/test/resources/gqlQueries/DrugWarnings_DrugWarningsQuery.gql
@@ -16,7 +16,5 @@ query DrugWarningsQuery($chemblId: String!) {
url
}
}
- hasBeenWithdrawn
- blackBoxWarning
}
}
diff --git a/test/resources/gqlQueries/DrugWarnings_DrugWarningsSummaryFragment.gql b/test/resources/gqlQueries/DrugWarnings_DrugWarningsSummaryFragment.gql
index c66be325..a8ff1f2a 100644
--- a/test/resources/gqlQueries/DrugWarnings_DrugWarningsSummaryFragment.gql
+++ b/test/resources/gqlQueries/DrugWarnings_DrugWarningsSummaryFragment.gql
@@ -1,4 +1,3 @@
fragment DrugWarningsSummaryFragment on Drug {
- hasBeenWithdrawn
- blackBoxWarning
+ id
}
diff --git a/test/resources/gqlQueries/KnownDrugs_KnownDrugsQuery.gql b/test/resources/gqlQueries/KnownDrugs_KnownDrugsQuery.gql
deleted file mode 100644
index 8621c918..00000000
--- a/test/resources/gqlQueries/KnownDrugs_KnownDrugsQuery.gql
+++ /dev/null
@@ -1,40 +0,0 @@
-query KnownDrugsQuery(
- $ensgId: String!
- $cursor: String
- $freeTextQuery: String
- $size: Int = 10
-) {
- target(ensemblId: $ensgId) {
- id
- knownDrugs(cursor: $cursor, freeTextQuery: $freeTextQuery, size: $size) {
- count
- cursor
- rows {
- phase
- status
- urls {
- name
- url
- }
- disease {
- id
- name
- }
- drug {
- id
- name
- mechanismsOfAction {
- rows {
- actionType
- targets {
- id
- }
- }
- }
- }
- drugType
- mechanismOfAction
- }
- }
- }
-}
diff --git a/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummary.gql b/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummary.gql
deleted file mode 100644
index f78e7e48..00000000
--- a/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummary.gql
+++ /dev/null
@@ -1,7 +0,0 @@
-fragment TargetKnownDrugsSummaryFragment on Target {
- knownDrugs {
- count
- uniqueDrugs
- uniqueDiseases
- }
-}
diff --git a/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummaryFragment.gql b/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummaryFragment.gql
deleted file mode 100644
index dba9c0b1..00000000
--- a/test/resources/gqlQueries/KnownDrugs_KnownDrugsSummaryFragment.gql
+++ /dev/null
@@ -1,7 +0,0 @@
-fragment DrugKnownDrugsSummaryFragment on Drug {
- knownDrugs {
- count
- uniqueTargets
- uniqueDiseases
- }
-}
diff --git a/test/resources/gqlQueries/SearchPage_SearchPageQuery.gql b/test/resources/gqlQueries/SearchPage_SearchPageQuery.gql
index 46d40dc8..80d934ec 100644
--- a/test/resources/gqlQueries/SearchPage_SearchPageQuery.gql
+++ b/test/resources/gqlQueries/SearchPage_SearchPageQuery.gql
@@ -71,8 +71,7 @@ query SearchPageQuery(
description
name
drugType
- maximumClinicalTrialPhase
- hasBeenWithdrawn
+ maximumClinicalStage
indications {
rows {
disease {