From e987153545d77b51b43900a0cbe3850766dbac8b Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Thu, 11 Jun 2026 12:27:22 +0100 Subject: [PATCH 1/2] feat(drug): expose synonyms/tradeNames as {label, source} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drug_molecule's `synonyms` and `tradeNames` changed from array to array> (opentargets/pts#142, tracking opentargets/issues#4414), and the POS ClickHouse drug table now stores Array(Tuple(label, source)) (opentargets/platform-output-support#130). Read both as Seq[LabelAndSource] (the existing type Target already uses) — the ClickHouse JSON read path parses the named tuple as a {label, source} object, the same way crossReferences (Tuple(source, ids)) already works. The Drug GraphQL type is derived, so the field type auto-updates to [LabelAndSource]; the synonyms/ tradeNames field docs are updated to describe the provenance. --- app/models/entities/Drug.scala | 5 +++-- app/models/gql/Objects.scala | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/models/entities/Drug.scala b/app/models/entities/Drug.scala index 999a84ac..2f5eaffe 100644 --- a/app/models/entities/Drug.scala +++ b/app/models/entities/Drug.scala @@ -1,5 +1,6 @@ package models.entities +import models.entities.Target.labelAndSourceImpF import play.api.libs.json._ import slick.jdbc.GetResult import utils.db.DbJsonParser.fromPositionedResult @@ -9,8 +10,8 @@ case class DrugReferences(source: String, ids: Seq[String]) case class Drug( id: String, name: String, - synonyms: Seq[String], - tradeNames: Seq[String], + synonyms: Seq[LabelAndSource], + tradeNames: Seq[LabelAndSource], childChemblIds: Option[Seq[String]], // Gone? drugType: String, crossReferences: Option[Seq[DrugReferences]], diff --git a/app/models/gql/Objects.scala b/app/models/gql/Objects.scala index e9bce57a..aa3a2296 100644 --- a/app/models/gql/Objects.scala +++ b/app/models/gql/Objects.scala @@ -1652,8 +1652,14 @@ object Objects extends OTLogging { ), DocumentField("id", "Drug or clinical candidate molecule identifier"), 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( + "synonyms", + "List of alternative names for the drug, each with its source (e.g. ChEMBL, or AACT for names mined from clinical trials)" + ), + DocumentField( + "tradeNames", + "List of brand names for the drug, each with its source" + ), DocumentField( "drugType", "Classification of the molecule's therapeutic category or chemical class (e.g. Antibody)" From 081536305924cebca31e169d2d7b66c720692987 Mon Sep 17 00:00:00 2001 From: ricardo Date: Wed, 17 Jun 2026 15:49:48 +0100 Subject: [PATCH 2/2] decouple drug label from target --- app/models/entities/Drug.scala | 8 +++++--- app/models/gql/Objects.scala | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/models/entities/Drug.scala b/app/models/entities/Drug.scala index 2f5eaffe..e69dbee1 100644 --- a/app/models/entities/Drug.scala +++ b/app/models/entities/Drug.scala @@ -1,17 +1,18 @@ package models.entities -import models.entities.Target.labelAndSourceImpF import play.api.libs.json._ import slick.jdbc.GetResult import utils.db.DbJsonParser.fromPositionedResult case class DrugReferences(source: String, ids: Seq[String]) +case class DrugLabelAndSource(label: String, source: String) + case class Drug( id: String, name: String, - synonyms: Seq[LabelAndSource], - tradeNames: Seq[LabelAndSource], + synonyms: Seq[DrugLabelAndSource], + tradeNames: Seq[DrugLabelAndSource], childChemblIds: Option[Seq[String]], // Gone? drugType: String, crossReferences: Option[Seq[DrugReferences]], @@ -24,6 +25,7 @@ case class Drug( object Drug { implicit val getResult: GetResult[Drug] = GetResult(fromPositionedResult[Drug]) implicit val DrugXRefImpW: OFormat[DrugReferences] = Json.format[DrugReferences] + implicit val drugLabelAndSourceImpF: OFormat[DrugLabelAndSource] = Json.format[DrugLabelAndSource] implicit val drugImplicitR: Reads[Drug] = Json.reads[Drug] implicit val drugImplicitW: OWrites[Drug] = Json.writes[Drug] } diff --git a/app/models/gql/Objects.scala b/app/models/gql/Objects.scala index aa3a2296..a9aff4d9 100644 --- a/app/models/gql/Objects.scala +++ b/app/models/gql/Objects.scala @@ -1646,6 +1646,13 @@ object Objects extends OTLogging { DocumentField("year", "Year when the warning was issued") ) + implicit val drugLabelAndSourceImp: ObjectType[Backend, DrugLabelAndSource] = + deriveObjectType[Backend, DrugLabelAndSource]( + ObjectTypeDescription("Label with source information"), + DocumentField("label", "Label value (e.g., synonym, symbol)"), + DocumentField("source", "Source database of the label") + ) + implicit lazy val drugImp: ObjectType[Backend, Drug] = deriveObjectType[Backend, Drug]( ObjectTypeDescription( "Core annotation for drug or clinical candidate molecules. A drug in the platform is understood as any bioactive molecule with drug-like properties included in the EMBL-EBI ChEMBL database. All ChEMBL molecules fullfilling any of the next criteria are included in the database: a) Molecules with a known indication. b) Molecules with a known mechanism of action c) ChEMBL molecules included in the DrugBank database d) Molecules that are acknowledged as chemical probes"