From ad9a54a3e47a25a70765f919fe009ff689fcf56a Mon Sep 17 00:00:00 2001 From: remo87 Date: Fri, 2 Aug 2024 11:47:32 +0100 Subject: [PATCH] 3379 cred set (#196) * credible set endpoint and entity * format files * add fectcher to clean cache and resolvers * add new fields * Filter documents * update id type * update to JsValue * format file * remove commeted code * undo Any type --- app/models/Backend.scala | 6 + app/models/GQLSchema.scala | 11 +- app/models/entities/CredibleSet.scala | 288 ++++++++++++++++++++++++++ app/models/gql/Arguments.scala | 2 + app/models/gql/Fetchers.scala | 17 +- app/models/gql/Objects.scala | 1 + 6 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 app/models/entities/CredibleSet.scala diff --git a/app/models/Backend.scala b/app/models/Backend.scala index 72f65e79..5211394d 100644 --- a/app/models/Backend.scala +++ b/app/models/Backend.scala @@ -140,6 +140,12 @@ class Backend @Inject() (implicit esRetriever.getByIds(indexName, ids, fromJsValue[VariantIndex]) } + def getCredSet(ids: Seq[String]): Future[IndexedSeq[JsValue]] = { + val indexName = getIndexOrDefault("credible_set") + + esRetriever.getByIds(indexName, ids, fromJsValue[JsValue]) + } + def getGwasIndexes(ids: Seq[String]): Future[IndexedSeq[JsValue]] = { val indexName = getIndexOrDefault("gwas_index") diff --git a/app/models/GQLSchema.scala b/app/models/GQLSchema.scala index 122e4ee1..3f7a4378 100644 --- a/app/models/GQLSchema.scala +++ b/app/models/GQLSchema.scala @@ -4,6 +4,7 @@ import play.api.Logging import play.api.libs.json._ import sangria.schema._ import entities._ +import models.entities.CredibleSet.credibleSetImp import models.entities.GwasIndex.gwasImp import sangria.execution.deferred._ @@ -28,7 +29,8 @@ object GQLSchema { indicationFetcher, goFetcher, variantFetcher, - gwasFetcher + gwasFetcher, + credSetFetcher ) val query: ObjectType[Backend, Unit] = ObjectType( @@ -149,6 +151,13 @@ object GQLSchema { description = Some("Return a Gwas Index Study"), arguments = studyId :: Nil, resolve = ctx => gwasFetcher.deferOpt(ctx.arg(studyId)) + ), + Field( + "credibleSet", + OptionType(credibleSetImp), + description = None, + arguments = credibleSetId :: Nil, + resolve = ctx => credSetFetcher.deferOpt(ctx.arg(credibleSetId)) ) ) ) diff --git a/app/models/entities/CredibleSet.scala b/app/models/entities/CredibleSet.scala new file mode 100644 index 00000000..a7451771 --- /dev/null +++ b/app/models/entities/CredibleSet.scala @@ -0,0 +1,288 @@ +package models.entities + +import models.Backend +import models.entities.GwasIndex.gwasImp +import models.gql.Fetchers.{gwasFetcher, targetsFetcher, variantFetcher} +import models.gql.Objects.{logger, targetImp, variantIndexImp} +import play.api.Logging +import play.api.libs.json.{JsValue, Json, OFormat, OWrites} +import sangria.schema.{ + Field, + FloatType, + IntType, + ListType, + ObjectType, + OptionType, + StringType, + fields +} + +case class Locus( + variantId: Option[String], + posteriorProbability: Option[Double], + pValueMantissa: Option[Double], + pValueExponent: Option[Int], + logBF: Option[Double], + beta: Option[Double], + standardError: Option[Double], + is95CredibleSet: Option[Boolean], + is99CredibleSet: Option[Boolean], + r2Overall: Option[Double] +) + +case class LdSet( + tagVariantId: Option[String], + r2Overall: Option[Double] +) + +case class StrongestLocus2gene(geneId: String, score: Double) + +case class CredibleSet(studyLocusId: String, + variantId: Option[String], + chromosome: Option[String], + position: Option[Int], + region: Option[String], + studyId: Option[String], + beta: Option[Double], + zScore: Option[Double], + pValueMantissa: Option[Double], + pValueExponent: Option[Int], + effectAlleleFrequencyFromSource: Option[Double], + standardError: Option[Double], + subStudyDescription: Option[String], + qualityControls: Option[Seq[String]], + finemappingMethod: Option[String], + credibleSetIndex: Option[Int], + credibleSetlog10BF: Option[Double], + purityMeanR2: Option[Double], + purityMinR2: Option[Double], + locusStart: Option[Int], + locusEnd: Option[Int], + locus: Option[Seq[Locus]], + sampleSize: Option[Int], + strongestLocus2gene: Option[StrongestLocus2gene], + ldSet: Option[Seq[LdSet]], + studyType: Option[String], + traitFromSourceMappedIds: Option[Seq[String]], + qtlGeneId: Option[String] +) + +object CredibleSet extends Logging { + import sangria.macros.derive._ + + implicit val strongestLocus2geneImp: ObjectType[Backend, StrongestLocus2gene] = + deriveObjectType[Backend, StrongestLocus2gene]( + ReplaceField( + "geneId", + Field( + "target", + OptionType(targetImp), + Some("Target"), + resolve = r => targetsFetcher.deferOpt(r.value.geneId) + ) + ) + ) + implicit val ldSetImp: ObjectType[Backend, LdSet] = + deriveObjectType[Backend, LdSet]() + implicit val locusImp: ObjectType[Backend, Locus] = deriveObjectType[Backend, Locus]( + ReplaceField( + "variantId", + Field( + "variant", + OptionType(variantIndexImp), + description = None, + resolve = r => { + val variantId = (r.value.variantId) + logger.debug(s"Finding variant index: $variantId") + variantFetcher.deferOpt(variantId) + } + ) + ) + ) + + implicit val ldSetF: OFormat[LdSet] = Json.format[LdSet] + implicit val locusF: OFormat[Locus] = Json.format[Locus] + implicit val strongestLocus2geneF: OFormat[StrongestLocus2gene] = Json.format[StrongestLocus2gene] + val credibleSetImp: ObjectType[Backend, JsValue] = ObjectType( + "credibleSet", + "", + fields[Backend, JsValue]( + Field( + "studyLocusId", + StringType, + description = None, + resolve = js => (js.value \ "studyLocusId").as[String] + ), + Field( + "variant", + OptionType(variantIndexImp), + description = None, + resolve = js => { + val id = (js.value \ "variantId").asOpt[String] + logger.debug(s"Finding variant for id: $id") + variantFetcher.deferOpt(id) + } + ), + Field( + "chromosome", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "chromosome").asOpt[String] + ), + Field( + "position", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "position").asOpt[Int] + ), + Field( + "region", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "region").asOpt[String] + ), + Field( + "study", + OptionType(gwasImp), + description = Some("Gwas study"), + resolve = js => { + val studyId = (js.value \ "studyId").asOpt[String] + logger.debug(s"Finding gwas study: $studyId") + gwasFetcher.deferOpt(studyId) + } + ), + Field( + "beta", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "beta").asOpt[Double] + ), + Field( + "zScore", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "zScore").asOpt[Double] + ), + Field( + "pValueMantissa", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "pValueMantissa").asOpt[Double] + ), + Field( + "pValueExponent", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "pValueExponent").asOpt[Int] + ), + Field( + "effectAlleleFrequencyFromSource", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "effectAlleleFrequencyFromSource").asOpt[Double] + ), + Field( + "standardError", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "standardError").asOpt[Double] + ), + Field( + "subStudyDescription", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "subStudyDescription").asOpt[String] + ), + Field( + "qualityControls", + OptionType(ListType(StringType)), + description = None, + resolve = js => (js.value \ "qualityControls").asOpt[Seq[String]] + ), + Field( + "finemappingMethod", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "finemappingMethod").asOpt[String] + ), + Field( + "credibleSetIndex", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "credibleSetIndex").asOpt[Int] + ), + Field( + "credibleSetlog10BF", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "credibleSetlog10BF").asOpt[Double] + ), + Field( + "purityMeanR2", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "purityMeanR2").asOpt[Double] + ), + Field( + "purityMinR2", + OptionType(FloatType), + description = None, + resolve = js => (js.value \ "purityMinR2").asOpt[Double] + ), + Field( + "locusStart", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "locusStart").asOpt[Int] + ), + Field( + "locusEnd", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "locusEnd").asOpt[Int] + ), + Field( + "locus", + OptionType(ListType(locusImp)), + description = None, + resolve = js => (js.value \ "locus").asOpt[Seq[Locus]] + ), + Field( + "sampleSize", + OptionType(IntType), + description = None, + resolve = js => (js.value \ "sampleSize").asOpt[Int] + ), + Field( + "strongestLocus2gene", + OptionType(strongestLocus2geneImp), + description = None, + resolve = js => (js.value \ "strongestLocus2gene").asOpt[StrongestLocus2gene] + ), + Field( + "ldSet", + OptionType(ListType(ldSetImp)), + description = None, + resolve = js => (js.value \ "ldSet").asOpt[Seq[LdSet]] + ), + Field( + "studyType", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "studyType").asOpt[String] + ), + Field( + "traitFromSourceMappedIds", + OptionType(ListType(StringType)), + description = None, + resolve = js => (js.value \ "traitFromSourceMappedIds").asOpt[Seq[String]] + ), + Field( + "qtlGeneId", + OptionType(StringType), + description = None, + resolve = js => (js.value \ "qtlGeneId").asOpt[String] + ) + ) + ) +} diff --git a/app/models/gql/Arguments.scala b/app/models/gql/Arguments.scala index 1549540a..2840820e 100644 --- a/app/models/gql/Arguments.scala +++ b/app/models/gql/Arguments.scala @@ -65,6 +65,8 @@ object Arguments { Argument("goIds", ListInputType(StringType), description = "List of GO IDs, eg. GO:0005515") val variantId: Argument[String] = Argument("variantId", StringType, description = "Variant ID") val studyId: Argument[String] = Argument("studyId", StringType, description = "Study ID") + val credibleSetId: Argument[String] = + Argument("credibleSetId", StringType, description = "Credible Set ID") val indirectEvidences: Argument[Option[Boolean]] = Argument( "enableIndirect", diff --git a/app/models/gql/Fetchers.scala b/app/models/gql/Fetchers.scala index ce0ac023..ff931496 100644 --- a/app/models/gql/Fetchers.scala +++ b/app/models/gql/Fetchers.scala @@ -2,6 +2,7 @@ package models.gql import models.Helpers.fromJsValue import models.entities.{ + CredibleSet, Disease, Drug, Expressions, @@ -128,6 +129,19 @@ object Fetchers extends Logging { } ) + val credSetFetcherCache = FetcherCache.simple + val credSetFetcher: Fetcher[Backend, JsValue, JsValue, String] = { + implicit val credSetFetcherId: HasId[JsValue, String] = + HasId[JsValue, String](js => (js \ "studyLocusId").as[String]) + Fetcher( + config = + FetcherConfig.maxBatchSize(entities.Configuration.batchSize).caching(credSetFetcherCache), + fetch = (ctx: Backend, ids: Seq[String]) => { + ctx.getCredSet(ids) + } + ) + } + val gwasFetcherCache = FetcherCache.simple val gwasFetcher: Fetcher[Backend, JsValue, JsValue, String] = { implicit val gwasFetcherId: HasId[JsValue, String] = @@ -166,7 +180,8 @@ object Fetchers extends Logging { reactomeFetcherCache, expressionFetcherCache, otarProjectsFetcherCache, - soTermsFetcherCache + soTermsFetcherCache, + credSetFetcherCache ) fetchers.foreach(_.clear()) } diff --git a/app/models/gql/Objects.scala b/app/models/gql/Objects.scala index 0f4d2fad..b3321b60 100644 --- a/app/models/gql/Objects.scala +++ b/app/models/gql/Objects.scala @@ -4,6 +4,7 @@ import models._ import models.entities.Configuration._ import models.entities.Evidence.sequenceOntologyTermImp import models.entities.Evidences._ +import models.entities.GwasIndex.gwasImp import models.entities.Interactions._ import models.entities.Publications.publicationsImp import models.entities._