aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKseniya Tomskikh <ktomskih@datamonsters.co>2017-10-27 12:41:33 +0700
committerKseniya Tomskikh <ktomskih@datamonsters.co>2017-10-27 12:41:33 +0700
commitd9440a727edd25f2472754dc51b0206d6abbeba4 (patch)
tree1e7a123e5f28c7b5adfa4962971a550d247c28dd
parentb27ba47906e48e9fc59d65893c71309303f73fc8 (diff)
parentfde83eb31ef4f2c2334b41d3a727239c034bfd63 (diff)
downloadrest-query-d9440a727edd25f2472754dc51b0206d6abbeba4.tar.gz
rest-query-d9440a727edd25f2472754dc51b0206d6abbeba4.tar.bz2
rest-query-d9440a727edd25f2472754dc51b0206d6abbeba4.zip
Merge branch 'master' into PDSUI-2336
-rw-r--r--build.sbt2
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala41
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala31
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala7
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala5
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala6
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiPartialDocument.scala1
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala86
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala5
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPatientCriterion.scala1
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala39
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala24
-rw-r--r--src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala10
-rw-r--r--src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala12
-rw-r--r--src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala26
-rw-r--r--src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala10
-rw-r--r--src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala74
-rw-r--r--src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala5
27 files changed, 327 insertions, 86 deletions
diff --git a/build.sbt b/build.sbt
index da7b511..beefadd 100644
--- a/build.sbt
+++ b/build.sbt
@@ -15,7 +15,7 @@ lazy val core = (project in file("."))
"com.typesafe.scala-logging" %% "scala-logging" % "3.5.0",
"io.getquill" %% "quill-jdbc" % "1.2.1",
"io.github.cloudify" %% "spdf" % "1.4.0",
- "xyz.driver" %% "core" % "1.2.2",
+ "xyz.driver" %% "core" % "1.2.3",
"xyz.driver" %% "domain-model" % "0.17.8",
"ch.qos.logback" % "logback-classic" % "1.1.7",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.8.4",
diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
index 180ebf9..3eb1a65 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
@@ -144,7 +144,9 @@ object ACL extends PhiLogging {
object Hypothesis
extends BaseACL(
label = "hypothesis",
- read = Set(TrialSummarizer, TrialAdmin) ++ TreatmentMatchingRoles
+ read = Set(TrialSummarizer, TrialAdmin) ++ TreatmentMatchingRoles,
+ create = Set(TrialAdmin),
+ delete = Set(TrialAdmin)
)
object Criterion
diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala
index 7366151..9962edf 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala
@@ -6,6 +6,7 @@ import java.time.LocalDateTime
import slick.jdbc.{JdbcProfile, PositionedParameters, SQLActionBuilder, SetParameter}
import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential}
import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending}
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId}
import scala.concurrent.{ExecutionContext, Future}
@@ -44,6 +45,18 @@ object SlickQueryBuilder {
pp.setObject(v, JDBCType.BINARY.getVendorTypeNumber)
}
}
+
+ implicit def setLongIdQueryParameter[T]: SetParameter[LongId[T]] = SetParameter[LongId[T]] { (v, pp) =>
+ pp.setLong(v.id)
+ }
+
+ implicit def setStringIdQueryParameter[T]: SetParameter[StringId[T]] = SetParameter[StringId[T]] { (v, pp) =>
+ pp.setString(v.id)
+ }
+
+ implicit def setUuidIdQueryParameter[T]: SetParameter[UuidId[T]] = SetParameter[UuidId[T]] { (v, pp) =>
+ pp.setObject(v.id, JDBCType.BINARY.getVendorTypeNumber)
+ }
}
final case class SlickTableLink(keyColumnName: String, foreignTableName: String, foreignKeyColumnName: String)
@@ -160,7 +173,7 @@ sealed trait SlickQueryBuilderParameters {
def isNull(string: AnyRef) = Option(string).isEmpty || string.toString.toLowerCase == "null"
def escapeDimension(dimension: SearchFilterExpr.Dimension) = {
- s"$escapedTableName.$qs${dimension.name}$qs"
+ s"${dimension.tableName.map(t => s"$qs$databaseName$qs.$qs$t$qs").getOrElse(escapedTableName)}.$qs${dimension.name}$qs"
}
def filterToSqlMultiple(operands: Seq[SearchFilterExpr]) = operands.collect {
@@ -174,9 +187,9 @@ sealed trait SlickQueryBuilderParameters {
if (conditions.nonEmpty) {
val condition = conditions.head
if (first) {
- multipleSqlToAction(false, op, conditions.tail, condition)
+ multipleSqlToAction(first = false, op, conditions.tail, condition)
} else {
- multipleSqlToAction(false, op, conditions.tail, sql concat sql" #${op} " concat condition)
+ multipleSqlToAction(first = false, op, conditions.tail, sql concat sql" #${op} " concat condition)
}
} else sql
}
@@ -184,9 +197,9 @@ sealed trait SlickQueryBuilderParameters {
def concatenateParameters(sql: SQLActionBuilder, first: Boolean, tail: Seq[AnyRef]): SQLActionBuilder = {
if (tail.nonEmpty) {
if (!first) {
- concatenateParameters(sql concat sql""",${tail.head}""", false, tail.tail)
+ concatenateParameters(sql concat sql""",${tail.head}""", first = false, tail.tail)
} else {
- concatenateParameters(sql"""(${tail.head}""", false, tail.tail)
+ concatenateParameters(sql"""(${tail.head}""", first = false, tail.tail)
}
} else sql concat sql")"
}
@@ -196,10 +209,10 @@ sealed trait SlickQueryBuilderParameters {
sql""
case AllowAll =>
- sql"1"
+ sql"1=1"
case DenyAll =>
- sql"0"
+ sql"1=0"
case Atom.Binary(dimension, Eq, value) if isNull(value) =>
sql"#${escapeDimension(dimension)} is NULL"
@@ -232,17 +245,19 @@ sealed trait SlickQueryBuilderParameters {
case SearchFilterNAryOperation.NotIn => sql" not in "
}
- val formattedValues = if (values.nonEmpty) {
- concatenateParameters(sql"", true, values)
- } else sql"NULL"
- sql"#${escapeDimension(dimension)}" concat sqlOp concat formattedValues
+ if (values.nonEmpty) {
+ val formattedValues = concatenateParameters(sql"", first = true, values)
+ sql"#${escapeDimension(dimension)}" concat sqlOp concat formattedValues
+ } else {
+ sql"1=0"
+ }
case Intersection(operands) =>
- val filter = multipleSqlToAction(true, "and", filterToSqlMultiple(operands), sql"")
+ val filter = multipleSqlToAction(first = true, "and", filterToSqlMultiple(operands), sql"")
sql"(" concat filter concat sql")"
case Union(operands) =>
- val filter = multipleSqlToAction(true, "or", filterToSqlMultiple(operands), sql"")
+ val filter = multipleSqlToAction(first = true, "or", filterToSqlMultiple(operands), sql"")
sql"(" concat filter concat sql")"
}
}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
index fd1856b..37e7687 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
@@ -3,6 +3,7 @@ package xyz.driver.pdsuicommon.http
import akka.http.scaladsl.server._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model._
+import xyz.driver.core.app.DriverApp
import xyz.driver.core.rest.ContextHeaders
import xyz.driver.entities.users.AuthUserInfo
import xyz.driver.pdsuicommon.auth._
@@ -88,7 +89,7 @@ trait Directives {
val text = errorsResponseJsonFormat.write(err).toString()
HttpEntity(ContentTypes.`application/json`, text)
}
- RejectionHandler.default.mapRejectionResponse {
+ DriverApp.rejectionHandler.mapRejectionResponse {
case res @ HttpResponse(_, _, ent: HttpEntity.Strict, _) =>
res.copy(entity = wrapContent(ent.data.utf8String))
case x => x // pass through all other types of responses
diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala
index 85e9149..718a42d 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala
@@ -1,5 +1,7 @@
package xyz.driver.pdsuicommon.parsers
+import java.util.UUID
+
import xyz.driver.pdsuicommon.utils.Implicits.{toCharOps, toStringOps}
import fastparse.all._
import fastparse.core.Parsed
@@ -79,7 +81,7 @@ object SearchFilterParser {
}
private val numericOperatorParser: Parser[String] = {
- P(IgnoreCase("eq") | ((IgnoreCase("gt") | IgnoreCase("lt")) ~ IgnoreCase("eq").?)).!
+ P(IgnoreCase("eq") | IgnoreCase("noteq") | ((IgnoreCase("gt") | IgnoreCase("lt")) ~ IgnoreCase("eq").?)).!
}
private val naryOperatorParser: Parser[String] = P(IgnoreCase("in")).!
@@ -89,10 +91,8 @@ object SearchFilterParser {
case _ => true
}
- // Exclude Unicode "digits"
- private val digitsParser: Parser[String] = P(CharIn('0' to '9').rep(min = 1).!)
+ private val digitsParser: Parser[String] = P(CharIn('0' to '9').rep(min = 1).!) // Exclude Unicode "digits"
- // @TODO Make complex checking here
private val numberParser: Parser[String] = P(isPositiveParser ~ digitsParser.! ~ ("." ~ digitsParser).!.?).map {
case (false, intPart, Some(fracPart)) => s"-$intPart.${fracPart.tail}"
case (false, intPart, None) => s"-$intPart"
@@ -107,11 +107,20 @@ object SearchFilterParser {
private val booleanParser: Parser[Boolean] =
P((IgnoreCase("true") | IgnoreCase("false")).!.map(_.toBoolean))
+ private val hexDigit: Parser[String] = P((CharIn('a' to 'f') | CharIn('A' to 'F') | CharIn('0' to '9')).!)
+
+ private val uuidParser: Parser[UUID] =
+ P(
+ hexDigit.rep(8).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit
+ .rep(12)
+ .!).map {
+ case (group1, group2, group3, group4, group5) => UUID.fromString(s"$group1-$group2-$group3-$group4-$group5")
+ }
+
private val binaryAtomParser: Parser[SearchFilterExpr.Atom.Binary] = P(
- dimensionParser ~ whitespaceParser ~ (
- (numericOperatorParser.! ~ whitespaceParser ~ (longParser | booleanParser | numberParser.!)) |
- (commonOperatorParser.! ~ whitespaceParser ~ AnyChar.rep(min = 1).!)
- ) ~ End
+ dimensionParser ~ whitespaceParser ~
+ ((numericOperatorParser.! ~ whitespaceParser ~ (longParser | numberParser.!) ~ End) |
+ (commonOperatorParser.! ~ whitespaceParser ~ (uuidParser | booleanParser | AnyChar.rep(min = 1).!) ~ End))
).map {
case BinaryAtomFromTuple(atom) => atom
}
@@ -119,9 +128,9 @@ object SearchFilterParser {
private val nAryAtomParser: Parser[SearchFilterExpr.Atom.NAry] = P(
dimensionParser ~ whitespaceParser ~ (
naryOperatorParser ~ whitespaceParser ~
- (longParser.rep(min = 1, sep = ",") | booleanParser.rep(min = 1, sep = ",") | nAryValueParser.!.rep(min = 1,
- sep = ","))
- ) ~ End
+ ((longParser.rep(min = 1, sep = ",") ~ End) | (booleanParser.rep(min = 1, sep = ",") ~ End) |
+ (nAryValueParser.!.rep(min = 1, sep = ",") ~ End))
+ )
).map {
case NAryAtomFromTuple(atom) => atom
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala
index 352cf55..569375a 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala
@@ -17,7 +17,7 @@ final case class ExtractedData(id: LongId[ExtractedData] = LongId(0L),
object ExtractedData {
- final case class Meta(keyword: Meta.Keyword, evidence: Meta.Evidence)
+ final case class Meta(keyword: Option[Meta.Keyword], evidence: Option[Meta.Evidence])
object Meta {
final case class Evidence(pageRatio: Double, start: TextLayerPosition, end: TextLayerPosition)
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala
index 79a19ed..7027eef 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala
@@ -9,11 +9,11 @@ import xyz.driver.pdsuicommon.logging._
object PatientCriterion {
implicit def toPhiString(x: PatientCriterion): PhiString = {
import x._
- phi"PatientCriterion(id=$id, patientLabelId=$patientLabelId, trialId=${Unsafe(trialId)}, nctId=${Unsafe(nctId)}, " +
+ phi"PatientCriterion(id=$id, patientLabelId=$patientLabelId, trialId=${Unsafe(trialId)}, nctId=$nctId, " +
phi"criterionId=$criterionId, criterionValue=${Unsafe(criterionValue)}, " +
phi"isImplicitMatch=$criterionIsDefining), criterionIsDefining=${Unsafe(criterionIsDefining)}, " +
phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, " +
- phi"isVerified=${Unsafe(isVerified)}, lastUpdate=${Unsafe(lastUpdate)}"
+ phi"isVerified=${Unsafe(isVerified)}, lastUpdate=${Unsafe(lastUpdate)}, inclusion=${Unsafe(inclusion)}"
}
/**
@@ -52,7 +52,8 @@ final case class PatientCriterion(id: LongId[PatientCriterion],
verifiedEligibilityStatus: Option[LabelValue],
isVerified: Boolean,
isVisible: Boolean,
- lastUpdate: LocalDateTime) {
+ lastUpdate: LocalDateTime,
+ inclusion: Option[Boolean]) {
def isIneligibleForEv: Boolean = eligibilityStatus.contains(LabelValue.No) && isVerified
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
index 8376e34..98bd084 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
@@ -11,13 +11,14 @@ final case class ExportTrialLabelCriterion(criterionId: LongId[Criterion],
armIds: Set[LongId[EligibilityArm]],
criteria: String,
isCompound: Boolean,
- isDefining: Boolean)
+ isDefining: Boolean,
+ inclusion: Option[Boolean])
object ExportTrialLabelCriterion {
implicit def toPhiString(x: ExportTrialLabelCriterion): PhiString = {
import x._
phi"TrialLabelCriterion(criterionId=$criterionId, value=$value, labelId=$labelId, " +
- phi"criteria=${Unsafe(criteria)}, isCompound=$isCompound, isDefining=$isDefining)"
+ phi"criteria=${Unsafe(criteria)}, isCompound=$isCompound, isDefining=$isDefining), inclusion=${Unsafe(inclusion)}"
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
index 2c7d0e0..33da392 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
@@ -28,7 +28,8 @@ object export {
armIds = setOf(nextLongId[EligibilityArm]),
criteria = nextString(100),
isCompound = nextBoolean(),
- isDefining = nextBoolean()
+ isDefining = nextBoolean(),
+ inclusion = nextOption(nextBoolean())
)
def nextExportTrialWithLabels(): ExportTrialWithLabels =
diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala
index 86583c1..3a018fa 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala
@@ -245,13 +245,13 @@ object recordprocessing {
def nextExtractedDataMeta(): Meta = {
ExtractedData.Meta(
- nextExtractedDataMetaKeyword(),
- nextExtractedDataMetaEvidence()
+ nextOption(nextExtractedDataMetaKeyword()),
+ nextOption(nextExtractedDataMetaEvidence())
)
}
def nextExtractedDataMetaJson(): TextJson[Meta] =
- nextTextJson(ExtractedData.Meta(nextExtractedDataMetaKeyword(), nextExtractedDataMetaEvidence()))
+ nextTextJson(nextExtractedDataMeta())
def nextExtractedData(): ExtractedData = {
ExtractedData(
diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala
index 2a06998..94c41ff 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala
@@ -86,7 +86,8 @@ object treatmentmatching {
verifiedEligibilityStatus = generators.nextOption(fakes.entities.labels.nextLabelValue()),
isVerified = generators.nextBoolean(),
isVisible = generators.nextBoolean(),
- lastUpdate = nextLocalDateTime
+ lastUpdate = nextLocalDateTime,
+ inclusion = generators.nextOption(generators.nextBoolean())
)
def nextDraftPatientCriterion(): DraftPatientCriterion = DraftPatientCriterion(
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiPartialDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiPartialDocument.scala
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiPartialDocument.scala
@@ -0,0 +1 @@
+
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala
index 6b72cb8..d70ce6f 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala
@@ -3,6 +3,7 @@ package xyz.driver.pdsuidomain.formats.json
import spray.json._
import xyz.driver.entities.labels.Label
import xyz.driver.formats.json.labels._
+import xyz.driver.pdsuicommon.domain.LongId
import xyz.driver.pdsuidomain.entities.export.patient._
import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels}
import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm}
@@ -13,6 +14,14 @@ object export {
import document._
import record._
+ private def deserializationErrorFieldMessage(field: String, json: JsValue)(implicit className: String) = {
+ deserializationError(s"$className json object do not contain '$field' field: $json")
+ }
+
+ private def deserializationErrorEntityMessage(json: JsValue)(implicit className: String) = {
+ deserializationError(s"Expected Json Object as $className, but got $json")
+ }
+
implicit val patientLabelEvidenceDocumentFormat: RootJsonFormat[ExportPatientLabelEvidenceDocument] =
jsonFormat5(ExportPatientLabelEvidenceDocument.apply)
@@ -29,6 +38,8 @@ object export {
implicit val trialLabelCriterionFormat: RootJsonFormat[ExportTrialLabelCriterion] =
new RootJsonFormat[ExportTrialLabelCriterion] {
+ implicit val className: String = "ExportTrialLabelCriterion"
+
override def write(obj: ExportTrialLabelCriterion): JsValue =
JsObject(
"value" -> obj.value
@@ -43,40 +54,69 @@ object export {
"criterionText" -> obj.criteria.toJson,
"armIds" -> obj.armIds.toJson,
"isCompound" -> obj.isCompound.toJson,
- "isDefining" -> obj.isDefining.toJson
+ "isDefining" -> obj.isDefining.toJson,
+ "inclusion" -> obj.inclusion.toJson
)
override def read(json: JsValue): ExportTrialLabelCriterion = {
+ json match {
+ case JsObject(fields) =>
+ val value = fields
+ .get("value")
+ .map(_.convertTo[String])
+ .map {
+ case "Yes" => Option(true)
+ case "No" => Option(false)
+ case "Unknown" => Option.empty[Boolean]
+ }
+ .getOrElse(deserializationErrorFieldMessage("value", json))
- val fields = Seq("value", "labelId", "criterionId", "criterionText", "armIds", "isCompound", "isDefining")
-
- json.asJsObject.getFields(fields: _*) match {
- case Seq(JsString(valueString),
- labelId,
- criterionId,
- JsString(criterionText),
- JsArray(armIdsVector),
- JsBoolean(isCompound),
- JsBoolean(isDefining)) =>
- val value = valueString match {
- case "Yes" => Option(true)
- case "No" => Option(false)
- case "Unknown" => Option.empty[Boolean]
- }
+ val labelId = fields
+ .get("labelId")
+ .map(_.convertTo[LongId[Label]])
+ .getOrElse(deserializationErrorFieldMessage("labelId", json))
+
+ val criterionId = fields
+ .get("criterionId")
+ .map(_.convertTo[LongId[Criterion]])
+ .getOrElse(deserializationErrorFieldMessage("criterionId", json))
+
+ val criterionText = fields
+ .get("criterionText")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationErrorFieldMessage("criterionText", json))
+
+ val armIds = fields
+ .get("armIds")
+ .map(_.convertTo[Set[LongId[EligibilityArm]]])
+ .getOrElse(deserializationErrorFieldMessage("armIds", json))
+
+ val isCompound = fields
+ .get("isCompound")
+ .map(_.convertTo[Boolean])
+ .getOrElse(deserializationErrorFieldMessage("isCompound", json))
+
+ val isDefining = fields
+ .get("isDefining")
+ .map(_.convertTo[Boolean])
+ .getOrElse(deserializationErrorFieldMessage("isDefining", json))
+
+ val inclusion = fields
+ .get("inclusion")
+ .flatMap(_.convertTo[Option[Boolean]])
ExportTrialLabelCriterion(
- longIdFormat[Criterion].read(criterionId),
+ criterionId,
value,
- longIdFormat[Label].read(labelId),
- armIdsVector.map(longIdFormat[EligibilityArm].read).toSet,
+ labelId,
+ armIds,
criterionText,
isCompound,
- isDefining
+ isDefining,
+ inclusion
)
- case _ =>
- deserializationError(
- s"Cannot find required fields ${fields.mkString(", ")} in ExportTrialLabelCriterion object!")
+ case _ => deserializationErrorEntityMessage(json)
}
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala
index 5cd7527..14edd5d 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala
@@ -99,7 +99,8 @@ object intervention {
val deliveryMethod = fields
.get("deliveryMethod")
- .map(_.convertTo[String])
+ .map(_.convertTo[Option[String]])
+ .getOrElse(orig.intervention.deliveryMethod)
val origIntervention = orig.intervention
val arms = fields
@@ -112,7 +113,7 @@ object intervention {
typeId = typeId.orElse(origIntervention.typeId),
dosage = dosage.getOrElse(origIntervention.dosage),
isActive = isActive.getOrElse(origIntervention.isActive),
- deliveryMethod = deliveryMethod.orElse(origIntervention.deliveryMethod)
+ deliveryMethod = deliveryMethod
),
arms = arms.getOrElse(orig.arms)
)
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPatientCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPatientCriterion.scala
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPatientCriterion.scala
@@ -0,0 +1 @@
+
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala
index fc0b725..fbefd33 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala
@@ -56,7 +56,8 @@ object patientcriterion {
"verifiedEligibilityStatus" -> obj.patientCriterion.verifiedEligibilityStatus.toJson,
"isVerified" -> obj.patientCriterion.isVerified.toJson,
"isVisible" -> obj.patientCriterion.isVisible.toJson,
- "lastUpdate" -> obj.patientCriterion.lastUpdate.toJson
+ "lastUpdate" -> obj.patientCriterion.lastUpdate.toJson,
+ "inclusion" -> obj.patientCriterion.inclusion.toJson
)
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala
index 9a8dc9c..b6ed103 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala
@@ -15,6 +15,7 @@ object record {
import common._
implicit val recordStatusFormat = new EnumJsonFormat[Status](
+ "PreCleaning" -> Status.PreCleaning,
"Unprocessed" -> Status.Unprocessed,
"PreOrganized" -> Status.PreOrganized,
"New" -> Status.New,
@@ -93,7 +94,7 @@ object record {
val endOriginalPage = fields
.get("endOriginalPage")
- .map(_.convertTo[Double])
+ .flatMap(_.convertTo[Option[Double]])
Duplicate(
startPage = startPage,
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala
index 52cd6c8..572edb6 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala
@@ -2,12 +2,21 @@ package xyz.driver.pdsuidomain.services
import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.domain.UuidId
import xyz.driver.pdsuicommon.error.DomainError
import xyz.driver.pdsuidomain.entities.Hypothesis
import scala.concurrent.Future
object HypothesisService {
+ trait DefaultNotFoundError {
+ def userMessage: String = "Hypothesis not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
sealed trait GetListReply
object GetListReply {
final case class EntityList(xs: Seq[Hypothesis], totalFound: Int) extends GetListReply
@@ -16,6 +25,32 @@ object HypothesisService {
def userMessage: String = "Access denied"
}
}
+
+ sealed trait CreateReply
+ object CreateReply {
+ final case class Created(x: Hypothesis) extends CreateReply
+
+ type Error = CreateReply with DomainError
+
+ case object AuthorizationError
+ extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ final case class CommonError(userMessage: String) extends CreateReply with DomainError
+ }
+
+ sealed trait DeleteReply
+ object DeleteReply {
+ case object Deleted extends DeleteReply
+
+ type Error = DeleteReply with DomainError
+
+ case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ final case class CommonError(userMessage: String) extends DeleteReply with DomainError
+ }
}
trait HypothesisService {
@@ -24,4 +59,8 @@ trait HypothesisService {
def getAll(sorting: Option[Sorting] = None)(
implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def create(draftHypothesis: Hypothesis)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ def delete(id: UuidId[Hypothesis])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply]
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala
index e0efcd1..e23449c 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala
@@ -85,7 +85,8 @@ class FakeTrialService extends TrialService {
generators.setOf(LongId[EligibilityArm](generators.nextInt(999999).toLong)),
generators.nextName().value,
generators.nextBoolean(),
- generators.nextBoolean()
+ generators.nextBoolean(),
+ generators.nextOption(generators.nextBoolean())
))
)
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala
index bf42f40..8e75c76 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala
@@ -59,9 +59,9 @@ trait RestHelper {
def exprToQuery(expr: SearchFilterExpr): Seq[(String, String)] = expr match {
case SearchFilterExpr.Empty => Seq.empty
case SearchFilterExpr.Atom.Binary(dimension, op, value) =>
- Seq("filters" -> s"${dimension.name} ${opToString(op)} $value")
+ Seq("filters" -> s"${dimension.tableName.fold("")(t => s"$t.") + dimension.name} ${opToString(op)} $value")
case SearchFilterExpr.Atom.NAry(dimension, SearchFilterNAryOperation.In, values) =>
- Seq("filters" -> s"${dimension.name} in ${values.mkString(",")}")
+ Seq("filters" -> s"${dimension.tableName.fold("")(t => s"$t.") + dimension.name} in ${values.mkString(",")}")
case SearchFilterExpr.Intersection(ops) =>
ops.flatMap(op => exprToQuery(op))
case expr => sys.error(s"No parser available for filter expression $expr.")
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala
index a352053..73abb0e 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala
@@ -1,11 +1,14 @@
package xyz.driver.pdsuidomain.services.rest
+import akka.http.scaladsl.marshalling.Marshal
+
import scala.concurrent.{ExecutionContext, Future}
import akka.http.scaladsl.model._
import akka.stream.Materializer
import xyz.driver.core.rest._
import xyz.driver.pdsuicommon.auth._
import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.UuidId
import xyz.driver.pdsuidomain.ListResponse
import xyz.driver.pdsuidomain.entities.Hypothesis
import xyz.driver.pdsuidomain.services.HypothesisService
@@ -31,4 +34,25 @@ class RestHypothesisService(transport: ServiceTransport, baseUri: Uri)(
}
}
+ def create(draftHypothesis: Hypothesis)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] = {
+ for {
+ entity <- Marshal(draftHypothesis).to[RequestEntity]
+ request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/hypothesis")).withEntity(entity)
+ response <- transport.sendRequestGetResponse(requestContext)(request)
+ reply <- apiResponse[Hypothesis](response)
+ } yield {
+ CreateReply.Created(reply)
+ }
+ }
+
+ def delete(id: UuidId[Hypothesis])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] = {
+ val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/hypothesis/$id"))
+ for {
+ response <- transport.sendRequestGetResponse(requestContext)(request)
+ _ <- apiResponse[HttpEntity](response)
+ } yield {
+ DeleteReply.Deleted
+ }
+ }
+
}
diff --git a/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala
index ac5eec1..0209222 100644
--- a/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala
@@ -1,5 +1,7 @@
package xyz.driver.pdsuicommon.parsers
+import java.util.UUID
+
import xyz.driver.pdsuicommon.db.SearchFilterExpr.Dimension
import xyz.driver.pdsuicommon.db.{SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation}
import xyz.driver.pdsuicommon.utils.Implicits.toStringOps
@@ -126,6 +128,14 @@ class SearchFilterParserSuite extends FreeSpecLike with Checkers {
}
}
+ "actual patientId uuid" - {
+ "should parse the full UUID as java.util.UUID type" in {
+ val filter = SearchFilterParser.parse(Seq("filters" -> "patientId EQ 4b4879f7-42b3-4b7c-a685-5c97d9e69e7c"))
+ assert(filter === Success(SearchFilterExpr.Atom.Binary(
+ Dimension(None, "patient_id"), Eq, UUID.fromString("4b4879f7-42b3-4b7c-a685-5c97d9e69e7c"))))
+ }
+ }
+
"all operators" - {
"should be parsed with numeric values" in check {
val testQueryGen = queryGen(
diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala
index 1f024c3..c976243 100644
--- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala
@@ -92,7 +92,8 @@ class ExportFormatSuite extends FlatSpec with Matchers {
armIds = Set(LongId(1), LongId(2)),
criteria = "criteria 10 text",
isCompound = false,
- isDefining = false
+ isDefining = false,
+ inclusion = Some(false)
),
ExportTrialLabelCriterion(
criterionId = LongId(11),
@@ -101,7 +102,8 @@ class ExportFormatSuite extends FlatSpec with Matchers {
armIds = Set(LongId(2)),
criteria = "criteria 11 text",
isCompound = true,
- isDefining = false
+ isDefining = false,
+ inclusion = None
)
)
val trialWithLabels = ExportTrialWithLabels(
@@ -117,8 +119,10 @@ class ExportFormatSuite extends FlatSpec with Matchers {
writtenJson should be(
"""{"nctId":"NCT000001","trialId":"40892a07-c638-49d2-9795-1edfefbbcc7c","lastReviewed":"2017-08-10T18:00Z",
"labelVersion":1,"arms":[{"armId":1,"armName":"arm 1","diseaseList":["Breast"]},{"armId":2,"armName":"arm 2","diseaseList":["Breast"]}],"criteria":[
- {"value":"Yes","labelId":21,"criterionId":10,"criterionText":"criteria 10 text","armIds":[1,2],"isCompound":false,"isDefining":false},
- {"value":"Unknown","labelId":21,"criterionId":11,"criterionText":"criteria 11 text","armIds":[2],"isCompound":true,"isDefining":false}]}""".parseJson)
+ {"value":"Yes","labelId":21,"criterionId":10,"criterionText":"criteria 10 text","armIds":[1,2],"isCompound":false,
+ "isDefining":false,"inclusion":false},
+ {"value":"Unknown","labelId":21,"criterionId":11,"criterionText":"criteria 11 text","armIds":[2],"isCompound":true,
+ "isDefining":false,"inclusion":null}]}""".parseJson)
}
}
diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala
index bc20280..d1d8d44 100644
--- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala
@@ -17,8 +17,18 @@ class ExtractedDataFormatSuite extends FlatSpec with Matchers {
documentId = LongId(101),
keywordId = Some(LongId(201)),
evidenceText = Some("evidence text"),
- meta = None
- )
+ meta = Option(TextJson(Meta(
+ evidence = None,
+ keyword =
+ Some(Meta.Keyword(
+ page = 1,
+ pageRatio = Some(1.6161616161616161d),
+ index = 0,
+ sortIndex = "1080000"
+ ))
+ )
+ )))
+
val extractedDataLabels = List(
ExtractedDataLabel(
id = LongId(1),
@@ -43,11 +53,13 @@ class ExtractedDataFormatSuite extends FlatSpec with Matchers {
writtenJson should be(
"""{"id":1,"documentId":101,"keywordId":201,"evidence":"evidence text","meta":null,
- "labels":[{"id":null,"categoryId":null,"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}]}""".parseJson)
+ "labels":[{"id":null,"categoryId":null,"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}],
+ "meta":{"keyword":{"index":0,"page":1,"pageRatio":1.6161616161616161,"sortIndex":"1080000"}}}""".parseJson)
val createExtractedDataJson =
"""{"documentId":101,"keywordId":201,"evidence":"evidence text",
- "labels":[{"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}]}""".parseJson
+ "labels":[{"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}],
+ "meta":{"keyword":{"index":0,"page":1,"pageRatio":1.6161616161616161,"sortIndex":"1080000"}}}""".parseJson
val expectedCreatedExtractedData = origRichExtractedData.copy(
extractedData = extractedData.copy(id = LongId(0)),
labels = extractedDataLabels.map(_.copy(id = LongId(0), dataId = LongId(0)))
@@ -80,12 +92,12 @@ class ExtractedDataFormatSuite extends FlatSpec with Matchers {
evidenceText = Some("new evidence text"),
meta = Some(
TextJson(Meta(
- keyword = Meta.Keyword(page = 1, pageRatio = None, index = 2, sortIndex = "ASC"),
- evidence = Meta.Evidence(
+ keyword = Some(Meta.Keyword(page = 1, pageRatio = None, index = 2, sortIndex = "ASC")),
+ evidence = Some(Meta.Evidence(
pageRatio = 1.0,
start = Meta.TextLayerPosition(page = 1, index = 3, offset = 2),
end = Meta.TextLayerPosition(page = 2, index = 3, offset = 10)
- )
+ ))
)))
),
labels = updatedExtractedDataLabels
diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala
index ac01c34..015c7b5 100644
--- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala
@@ -19,7 +19,7 @@ class InterventionFormatSuite extends FlatSpec with Matchers {
dosage = "",
originalDosage = "",
isActive = true,
- deliveryMethod = Some("pill")
+ deliveryMethod = Some("Inhalation")
)
val arms = List(
InterventionArm(interventionId = intervention.id, armId = LongId(20)),
@@ -34,11 +34,11 @@ class InterventionFormatSuite extends FlatSpec with Matchers {
writtenJson should be(
"""{"id":1,"name":"intervention name","typeId":10,"dosage":"","isActive":true,"arms":[20,21,22],
- "trialId":"NCT000001","deliveryMethod":"pill","originalName":"orig name","originalDosage":"","originalType":"orig type"}""".parseJson)
+ "trialId":"NCT000001","deliveryMethod":"Inhalation","originalName":"orig name","originalDosage":"","originalType":"orig type"}""".parseJson)
val createInterventionJson =
"""{"id":1,"name":"intervention name","typeId":10,"dosage":"","isActive":true,"arms":[20,21,22],
- "trialId":"NCT000001","deliveryMethod":"pill"}""".parseJson
+ "trialId":"NCT000001","deliveryMethod":"Inhalation"}""".parseJson
val parsedCreateIntervention = interventionFormat.read(createInterventionJson)
val expectedCreateIntervention = parsedCreateIntervention.copy(
intervention = intervention.copy(id = LongId(0), originalType = None, originalName = "intervention name"),
@@ -46,9 +46,9 @@ class InterventionFormatSuite extends FlatSpec with Matchers {
)
parsedCreateIntervention should be(expectedCreateIntervention)
- val updateInterventionJson = """{"dosage":"descr","arms":[21,22]}""".parseJson
+ val updateInterventionJson = """{"dosage":"descr","deliveryMethod":null,"arms":[21,22]}""".parseJson
val expectedUpdatedIntervention = orig.copy(
- intervention = intervention.copy(dosage = "descr"),
+ intervention = intervention.copy(dosage = "descr", deliveryMethod = None),
arms = List(
InterventionArm(interventionId = intervention.id, armId = LongId(21)),
InterventionArm(interventionId = intervention.id, armId = LongId(22))
diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala
index e811a29..b4e37a2 100644
--- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala
@@ -12,6 +12,80 @@ class MedicalRecordFormatSuite extends FlatSpec with Matchers {
import xyz.driver.pdsuidomain.formats.json.record._
import MedicalRecord._
+ "Json format for MedicalRecord.Meta" should "read and write correct JSON" in {
+ val duplicate1 = Meta.Duplicate(
+ startPage = 1.0d,
+ endPage = 2.0d,
+ startOriginalPage = 1.0d,
+ endOriginalPage = Some(2.0d)
+ )
+
+ val duplicate2 = Meta.Duplicate(
+ startPage = 1.0d,
+ endPage = 2.0d,
+ startOriginalPage = 1.0d,
+ endOriginalPage = None
+ )
+
+ val reorder = Meta.Reorder(
+ Seq(1, 2)
+ )
+
+ val rotation = Meta.Rotation(
+ Map("item1" -> 1, "item2" -> 2)
+ )
+
+ val writtenDuplicateJson1 =
+ duplicateMetaFormat.write(duplicate1)
+
+ val writtenDuplicateJson2 =
+ duplicateMetaFormat.write(duplicate2)
+
+ val writtenReorderJson =
+ reorderMetaFormat.write(reorder)
+
+ val writtenRotationJson =
+ rotateMetaFormat.write(rotation)
+
+ writtenDuplicateJson1 should be(
+ """{"startOriginalPage":1.0,"endPage":2.0,"startPage":1.0,"type":"duplicate","endOriginalPage":2.0}""".parseJson)
+
+ writtenDuplicateJson2 should be(
+ """{"startOriginalPage":1.0,"endPage":2.0,"startPage":1.0,"type":"duplicate","endOriginalPage":null}""".parseJson)
+
+ writtenReorderJson should be(
+ """{"type":"reorder","items":[1,2]}""".parseJson)
+
+ writtenRotationJson should be(
+ """{"type":"rotation","items":{"item1":1,"item2":2}}""".parseJson)
+
+ val parsedDuplicateJson1 =
+ duplicateMetaFormat.read(writtenDuplicateJson1)
+
+ val parsedDuplicateJson2 =
+ duplicateMetaFormat.read(writtenDuplicateJson2)
+
+ val parsedReorderJson =
+ reorderMetaFormat.read(writtenReorderJson)
+
+ val parsedRotationJson =
+ rotateMetaFormat.read(writtenRotationJson)
+
+ duplicate1 should be(parsedDuplicateJson1)
+
+ duplicate2 should be(parsedDuplicateJson2)
+
+ reorder should be(parsedReorderJson)
+
+ rotation should be(parsedRotationJson)
+
+ duplicate1 should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(duplicate1)))
+ duplicate2 should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(duplicate2)))
+ reorder should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(reorder)))
+ rotation should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(rotation)))
+ }
+
+
"Json format for MedicalRecord" should "read and write correct JSON" in {
val orig = MedicalRecord(
id = LongId(1),
diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala
index 2e193c7..93284d9 100644
--- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala
@@ -26,7 +26,8 @@ class PatientCriterionFormatSuite extends FlatSpec with Matchers {
verifiedEligibilityStatus = None,
isVisible = true,
isVerified = true,
- lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00")
+ lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"),
+ inclusion = Some(true)
)
val arms = List(
PatientCriterionArm(patientCriterionId = LongId(1), armId = LongId(31), armName = "arm 31"),
@@ -38,7 +39,7 @@ class PatientCriterionFormatSuite extends FlatSpec with Matchers {
writtenJson should be(
"""{"id":1,"labelId":21,"nctId":"NCT00001","criterionId":101,"criterionText":"criterion text","criterionValue":"Yes",
"criterionIsDefining":false,"criterionIsCompound":false,"eligibilityStatus":"Yes","verifiedEligibilityStatus":null,
- "isVisible":true,"isVerified":true,"lastUpdate":"2017-08-10T18:00Z","arms":["arm 31","arm 32"]}""".parseJson)
+ "isVisible":true,"isVerified":true,"lastUpdate":"2017-08-10T18:00Z","arms":["arm 31","arm 32"],"inclusion":true}""".parseJson)
val updatePatientCriterionJson = """{"verifiedEligibilityStatus":"No"}""".parseJson
val expectedUpdatedPatientCriterion = orig.copy(verifiedEligibilityStatus = Some(LabelValue.No))