diff options
author | vlad <vlad@driver.xyz> | 2018-01-25 14:12:31 -0800 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2018-01-25 14:12:31 -0800 |
commit | a0877d81ca2844d75dc361b5ce7c99afacd6e25f (patch) | |
tree | 8fe49f45cbcddbbb9a3d167099abe7aa2625e56b /src/main/scala/xyz/driver/pdsuicommon | |
parent | 46a22e9ab324a0068a85952cdc809800f360f445 (diff) | |
download | rest-query-a0877d81ca2844d75dc361b5ce7c99afacd6e25f.tar.gz rest-query-a0877d81ca2844d75dc361b5ce7c99afacd6e25f.tar.bz2 rest-query-a0877d81ca2844d75dc361b5ce7c99afacd6e25f.zip |
Extracting query library
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon')
68 files changed, 0 insertions, 3433 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/Config.scala b/src/main/scala/xyz/driver/pdsuicommon/Config.scala deleted file mode 100644 index 25686b8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/Config.scala +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.driver.pdsuicommon - -import pureconfig._ - -import scala.util.{Failure, Success, Try} - -object Config { - - implicit def productHint[T]: ProductHint[T] = ProductHint(ConfigFieldMapping(CamelCase, CamelCase)) - - def loadConfig[Config](implicit reader: ConfigReader[Config]): Try[Config] = pureconfig.loadConfig match { - case Right(x) => Success(x) - case Left(e) => Failure(new RuntimeException(e.toString)) - } - - def loadConfig[Config](namespace: String)(implicit reader: ConfigReader[Config]): Try[Config] = - pureconfig.loadConfig(namespace) match { - case Right(x) => Success(x) - case Left(e) => Failure(new RuntimeException(e.toString)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala deleted file mode 100644 index e4c907e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala +++ /dev/null @@ -1,280 +0,0 @@ -package xyz.driver.pdsuicommon.acl - -import xyz.driver.core.auth.Role -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.auth._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.logging._ - -/** - * @see https://driverinc.atlassian.net/wiki/display/RA/User+permissions#UserPermissions-AccessControlList - */ -object ACL extends PhiLogging { - - type AclCheck = Role => Boolean - - val Forbid: AclCheck = _ => false - - val Allow: AclCheck = _ => true - - val RepRoles: Set[Role] = Set[Role](RecordAdmin, RecordCleaner, RecordOrganizer, DocumentExtractor) - - val TcRoles: Set[Role] = Set[Role](TrialSummarizer, CriteriaCurator, TrialAdmin) - - val TreatmentMatchingRoles: Set[Role] = Set[Role](RoutesCurator, EligibilityVerifier, TreatmentMatchingAdmin) - - val PepRoles: Set[Role] = Set[Role](ResearchOncologist) - - val All: Set[Role] = RepRoles ++ TcRoles ++ TreatmentMatchingRoles ++ PepRoles + AdministratorRole - - // Common - - object UserHistory - extends BaseACL( - label = "user history", - read = Set(TreatmentMatchingAdmin) - ) - - object Queue - extends BaseACL( - label = "queue", - create = Set(AdministratorRole), - read = Set(AdministratorRole), - update = Set(AdministratorRole) - ) - - // REP - - object MedicalRecord - extends BaseACL( - label = "medical record", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = RepRoles - DocumentExtractor - ) - - object MedicalRecordHistory - extends BaseACL( - label = "medical record history", - read = Set(RecordAdmin) - ) - - object MedicalRecordIssue - extends BaseACL( - label = "medical record issue", - create = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - read = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - update = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - delete = Set(RecordCleaner, RecordOrganizer, RecordAdmin) - ) - - object Document - extends BaseACL( - label = "document", - create = Set(RecordOrganizer, RecordAdmin), - read = RepRoles - RecordCleaner ++ TreatmentMatchingRoles + ResearchOncologist, - update = RepRoles - RecordCleaner, - delete = Set(RecordOrganizer, RecordAdmin) - ) - - object DocumentHistory - extends BaseACL( - label = "document history", - read = Set(RecordAdmin) - ) - - object DocumentIssue - extends BaseACL( - label = "document issue", - create = Set(RecordAdmin, DocumentExtractor), - read = Set(RecordAdmin, DocumentExtractor), - update = Set(RecordAdmin, DocumentExtractor), - delete = Set(RecordAdmin, DocumentExtractor) - ) - - object ExtractedData - extends BaseACL( - label = "extracted data", - create = Set(DocumentExtractor, RecordAdmin), - read = Set(DocumentExtractor, RecordAdmin) ++ TreatmentMatchingRoles + ResearchOncologist, - update = Set(DocumentExtractor, RecordAdmin), - delete = Set(DocumentExtractor, RecordAdmin) - ) - - object ProviderType - extends BaseACL( - label = "provider type", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist - ) - - object DocumentType - extends BaseACL( - label = "document type", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist - ) - - object Message - extends BaseACL( - label = "message", - create = RepRoles ++ TreatmentMatchingRoles, - read = RepRoles ++ TreatmentMatchingRoles, - update = RepRoles ++ TreatmentMatchingRoles, - delete = RepRoles ++ TreatmentMatchingRoles - ) - - // TC - - object Trial - extends BaseACL( - label = "trial", - read = TcRoles ++ TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = TcRoles - ) - - object TrialHistory - extends BaseACL( - label = "trial history", - read = TcRoles - ) - - object TrialIssue - extends BaseACL( - label = "trial issue", - create = TcRoles, - read = TcRoles, - update = TcRoles, - delete = TcRoles - ) - - object StudyDesign - extends BaseACL( - label = "study design", - read = Set(TrialSummarizer, TrialAdmin) - ) - - object Hypothesis - extends BaseACL( - label = "hypothesis", - read = Set(TrialSummarizer, TrialAdmin) ++ TreatmentMatchingRoles, - create = Set(TrialAdmin), - delete = Set(TrialAdmin) - ) - - object Criterion - extends BaseACL( - label = "criterion", - create = Set(CriteriaCurator, TrialAdmin), - read = Set(CriteriaCurator, TrialAdmin, RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), - update = Set(CriteriaCurator, TrialAdmin), - delete = Set(CriteriaCurator, TrialAdmin) - ) - - object Arm - extends BaseACL( - label = "arm", - create = Set(TrialSummarizer, TrialAdmin), - read = TcRoles, - update = Set(TrialSummarizer, TrialAdmin), - delete = Set(TrialSummarizer, TrialAdmin) - ) - - object Intervention - extends BaseACL( - label = "intervention", - create = Set(TrialSummarizer, TrialAdmin), - read = Set(TrialSummarizer, TrialAdmin), - update = Set(TrialSummarizer, TrialAdmin), - delete = Set(TrialSummarizer, TrialAdmin) - ) - - object InterventionType - extends BaseACL( - label = "intervention type", - read = Set(TrialSummarizer, TrialAdmin) - ) - - // EV - - object Patient - extends BaseACL( - label = "patient", - read = TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = TreatmentMatchingRoles - ) - - object PatientHistory - extends BaseACL( - label = "patient history", - read = Set(TreatmentMatchingAdmin) - ) - - object PatientIssue - extends BaseACL( - label = "patient issue", - create = TreatmentMatchingRoles, - read = TreatmentMatchingRoles, - update = TreatmentMatchingRoles, - delete = TreatmentMatchingRoles - ) - - object PatientLabel - extends BaseACL( - label = "patient label", - read = TreatmentMatchingRoles + ResearchOncologist, - update = TreatmentMatchingRoles - ) - - object PatientCriterion - extends BaseACL( - label = "patient criterion", - read = TreatmentMatchingRoles + ResearchOncologist, - update = TreatmentMatchingRoles - ) - - object PatientLabelEvidence - extends BaseACL( - label = "patient label evidence", - read = TreatmentMatchingRoles + ResearchOncologist - ) - - object EligibleTrial - extends BaseACL( - label = "eligible trial", - read = Set(RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), - update = Set(RoutesCurator, TreatmentMatchingAdmin) - ) - - object PatientHypothesis - extends BaseACL( - label = "patient hypothesis", - read = Set(RoutesCurator, TreatmentMatchingAdmin), - update = Set(RoutesCurator, TreatmentMatchingAdmin) - ) - - // Utility code - - abstract class BaseACL(label: String, - create: AclCheck = Forbid, - read: AclCheck = Forbid, - update: AclCheck = Forbid, - delete: AclCheck = Forbid) { - - def isCreateAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("create", create)(requestContext.authenticatedUser.roles) - - def isReadAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("read", read)(requestContext.authenticatedUser.roles) - - def isUpdateAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("update", update)(requestContext.authenticatedUser.roles) - - def isDeleteAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("delete", delete)(requestContext.authenticatedUser.roles) - - private def check(action: String, isAllowed: AclCheck)(executorRoles: Set[Role]): Boolean = { - loggedError( - executorRoles.exists(isAllowed) || executorRoles.contains(AdministratorRole), - phi"${Unsafe(executorRoles.mkString(", "))} has no access to ${Unsafe(action)} a ${Unsafe(label)}" - ) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala deleted file mode 100644 index d069f86..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.compat - -final class EitherOps[A, B](val self: Either[A, B]) extends AnyVal { - - def map[B2](f: B => B2): Either[A, B2] = flatMap { x => - Right(f(x)) - } - - def flatMap[B2](f: B => Either[A, B2]): Either[A, B2] = self match { - case Left(x) => Left(x) - case Right(x) => f(x) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala deleted file mode 100644 index 147c9e8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala +++ /dev/null @@ -1,7 +0,0 @@ -package xyz.driver.pdsuicommon.compat - -object Implicits { - - implicit def toEitherOps[A, B](self: Either[A, B]): EitherOps[A, B] = new EitherOps(self) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala deleted file mode 100644 index a9430e3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala +++ /dev/null @@ -1,124 +0,0 @@ -package xyz.driver.pdsuicommon.computation - -import scala.concurrent.{ExecutionContext, Future} - -/** - * Takes care of computations - * - * Success(either) - the computation will be continued. - * Failure(error) - the computation was failed with unhandled error. - * - * Either[Result, T]: - * Left(result) is a final and handled result, another computations (map, flatMap) will be ignored. - * Right(T) is a current result. Functions in map/flatMap will continue the computation. - * - * Example: - * {{{ - * import scala.concurrent.ExecutionContext.Implicits.global - * import scala.concurrent.{ExecutionContext, Future} - * import xyz.driver.pdsuicommon.computation.Computation - * - * def successful = for { - * x <- Computation.continue(1) - * y <- Computation.continue(2) - * } yield s"\$x + \$y" - * - * // Prints "Success(1 + 2)" - * successful.join.onComplete(print) - * - * def failed = for { - * x <- Computation.abort("Failed on x") - * _ = print("Second step") - * y <- Computation.continue(2) - * } yield s"\$x + \$y" - * - * // Prints "Success(Failed on x)" - * failed.join.onComplete(print) - * }}} - * - * TODO: Make future private - * - * @param future The final flow in a future. - * @tparam R Type of result for aborted computation. - * @tparam T Type of result for continued computation. - */ -final case class Computation[+R, +T](future: Future[Either[R, T]]) { - - def flatMap[R2, T2](f: T => Computation[R2, T2])(implicit ec: ExecutionContext, ev: R <:< R2): Computation[R2, T2] = { - Computation(future.flatMap { - case Left(x) => Future.successful(Left(x)) - case Right(x) => f(x).future - }) - } - - def processExceptions[R2](f: PartialFunction[Throwable, R2])(implicit ev1: R <:< R2, - ec: ExecutionContext): Computation[R2, T] = { - val strategy = f.andThen(x => Left(x): Either[R2, T]) - val castedFuture: Future[Either[R2, T]] = future.map { - case Left(x) => Left(x) - case Right(x) => Right(x) - } - Computation(castedFuture.recover(strategy)) - } - - def map[T2](f: T => T2)(implicit ec: ExecutionContext): Computation[R, T2] = flatMap { a => - Computation.continue(f(a)) - } - - def mapLeft[R2](f: R => R2)(implicit ec: ExecutionContext): Computation[R2, T] = { - Computation(future.map { - case Left(x) => Left(f(x)) - case Right(x) => Right(x) - }) - } - - def mapAll[R2, T2](onLeft: R => Computation[R2, T2])(onRight: T => Computation[R2, T2])( - onFailure: () => Computation[R2, T2])(implicit ec: ExecutionContext): Computation[R2, T2] = { - - Computation(future.flatMap(_.fold(onLeft, onRight).future).recoverWith { - case _ => onFailure().future - }) - } - - def andThen(f: T => Any)(implicit ec: ExecutionContext): Computation[R, T] = map { a => - f(a) - a - } - - def filter(f: T => Boolean)(implicit ec: ExecutionContext): Computation[R, T] = map { a => - if (f(a)) a - else throw new NoSuchElementException("When filtering") - } - - def withFilter(f: T => Boolean)(implicit ec: ExecutionContext): Computation[R, T] = filter(f) - - def foreach[T2](f: T => T2)(implicit ec: ExecutionContext): Unit = future.foreach { - case Right(x) => f(x) - case _ => - } - - def toFuture[R2](resultFormatter: T => R2)(implicit ec: ExecutionContext, ev: R <:< R2): Future[R2] = future.map { - case Left(x) => x - case Right(x) => resultFormatter(x) - } - - def toFuture[R2](implicit ec: ExecutionContext, ev1: R <:< R2, ev2: T <:< R2): Future[R2] = future.map { - case Left(x) => x - case Right(x) => x - } -} - -object Computation { - - def continue[T](x: T): Computation[Nothing, T] = Computation(Future.successful(Right(x))) - - def abort[R](result: R): Computation[R, Nothing] = Computation(Future.successful(Left(result))) - - def fail(exception: Throwable): Computation[Nothing, Nothing] = Computation(Future.failed(exception)) - - def fromFuture[T](input: Future[T])(implicit ec: ExecutionContext): Computation[Nothing, T] = Computation { - input.map { x => - Right(x) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala deleted file mode 100644 index 8213262..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala +++ /dev/null @@ -1,84 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.logging._ - -import scala.concurrent.Future - -object BridgeUploadQueue { - - /** - * @param kind For example documents - * @param tag For example, a patient's id: 1 - * @param attempts Which attempt - * @param created When the task was created - * @param nextAttempt Time of the next attempt - */ - final case class Item(kind: String, - tag: String, - created: LocalDateTime, - attempts: Int, - nextAttempt: LocalDateTime, - completed: Boolean, - dependencyKind: Option[String], - dependencyTag: Option[String]) { - - def dependency: Option[Dependency] = { - dependencyKind - .zip(dependencyTag) - .headOption - .map(Function.tupled(Dependency.apply)) - } - - } - - object Item { - - implicit def toPhiString(x: Item): PhiString = { - import x._ - phi"BridgeUploadQueue.Item(kind=${Unsafe(kind)}, tag=${Unsafe(tag)}, " + - phi"attempts=${Unsafe(attempts)}, start=$created, nextAttempt=$nextAttempt, completed=$completed, " + - phi"dependency=$dependency)" - } - - def apply(kind: String, tag: String, dependency: Option[Dependency] = None): Item = { - val now = LocalDateTime.now() - - Item( - kind = kind, - tag = tag, - created = now, - attempts = 0, - nextAttempt = now, - completed = false, - dependencyKind = dependency.map(_.kind), - dependencyTag = dependency.map(_.tag) - ) - } - - } - - final case class Dependency(kind: String, tag: String) - - object Dependency { - - implicit def toPhiString(x: Dependency): PhiString = { - import x._ - phi"Dependency(kind=${Unsafe(kind)}, tag=${Unsafe(tag)})" - } - } -} - -trait BridgeUploadQueue { - - def add(item: Item): Future[Item] - - def get(kind: String): Future[Option[Item]] - - def complete(kind: String, tag: String): Future[Unit] - - def tryRetry(item: Item): Future[Option[Item]] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala deleted file mode 100644 index 6659088..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala +++ /dev/null @@ -1,93 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.io.Closeable -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.atomic.AtomicBoolean -import java.util.{Timer, TimerTask} - -import com.typesafe.scalalogging.StrictLogging -import org.slf4j.MDC -import xyz.driver.pdsuicommon.error.ExceptionFormatter -import xyz.driver.pdsuicommon.utils.RandomUtils - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Failure, Success, Try} - -class Cron(settings: Cron.Settings) extends Closeable with StrictLogging { - - import Cron._ - - private val timer = new Timer("cronTimer", true) - - private val jobs = ConcurrentHashMap.newKeySet[String]() - - def register(name: String)(job: () => Future[Unit])(implicit ec: ExecutionContext): Unit = { - logger.trace("register({})", name) - val disableList = settings.disable.split(",").map(_.trim).toList - if (disableList.contains(name)) logger.info("The task '{}' is disabled", name) - else { - settings.intervals.get(name) match { - case None => - logger.error("Can not find an interval for task '{}', check the settings", name) - throw new IllegalArgumentException(s"Can not find an interval for task '$name', check the settings") - - case Some(period) => - logger.info("register a new task '{}' with a period of {}ms", name, period.toMillis.asInstanceOf[AnyRef]) - timer.schedule(new SingletonTask(name, job), 0, period.toMillis) - } - } - - jobs.add(name) - } - - /** - * Checks unused jobs - */ - def verify(): Unit = { - import scala.collection.JavaConverters._ - - val unusedJobs = settings.intervals.keySet -- jobs.asScala.toSet - unusedJobs.foreach { job => - logger.warn(s"The job '$job' is listed, but not registered or ignored") - } - } - - override def close(): Unit = { - timer.cancel() - } -} - -object Cron { - - final case class Settings(disable: String, intervals: Map[String, FiniteDuration]) - - private class SingletonTask(taskName: String, job: () => Future[Unit])(implicit ec: ExecutionContext) - extends TimerTask with StrictLogging { - - private val isWorking = new AtomicBoolean(false) - - override def run(): Unit = { - if (isWorking.compareAndSet(false, true)) { - MDC.put("userId", "cron") - MDC.put("requestId", RandomUtils.randomString(15)) - - logger.info("Start '{}'", taskName) - Try { - job() - .andThen { - case Success(_) => logger.info("'{}' is completed", taskName) - case Failure(e) => logger.error(s"Job '{}' is failed: ${ExceptionFormatter.format(e)}", taskName) - } - .onComplete(_ => isWorking.set(false)) - } match { - case Success(_) => - case Failure(e) => - logger.error("Can't start '{}'", taskName, e) - } - } else { - logger.debug("The previous job '{}' is in progress", taskName) - } - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala deleted file mode 100644 index 658b5b1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala +++ /dev/null @@ -1,37 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.util.concurrent.LinkedBlockingQueue -import java.util.function.Predicate - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.logging.PhiLogging - -import scala.collection.JavaConverters._ -import scala.concurrent.Future - -/** - * Use it only for tests - */ -class InMemoryBridgeUploadQueue extends BridgeUploadQueue with PhiLogging { - - private val queue = new LinkedBlockingQueue[Item]() - - override def add(item: Item): Future[Item] = { - queue.add(item) - Future.successful(item) - } - - override def tryRetry(item: Item): Future[Option[Item]] = Future.successful(Some(item)) - - override def get(kind: String): Future[Option[Item]] = { - val r = queue.iterator().asScala.find(_.kind == kind) - Future.successful(r) - } - - override def complete(kind: String, tag: String): Future[Unit] = { - queue.removeIf(new Predicate[Item] { - override def test(t: Item): Boolean = t.kind == kind && t.tag == tag - }) - Future.successful(()) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala deleted file mode 100644 index 3dee8ea..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import org.slf4j.MDC - -import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} - -object MdcExecutionContext { - def from(orig: ExecutionContext): ExecutionContext = new MdcExecutionContext(orig) -} - -class MdcExecutionContext(orig: ExecutionContext) extends ExecutionContextExecutor { - - def execute(runnable: Runnable): Unit = { - val parentMdcContext = MDC.getCopyOfContextMap - - orig.execute(new Runnable { - def run(): Unit = { - val saveMdcContext = MDC.getCopyOfContextMap - setContextMap(parentMdcContext) - - try { - runnable.run() - } finally { - setContextMap(saveMdcContext) - } - } - }) - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - def reportFailure(t: Throwable): Unit = orig.reportFailure(t) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala deleted file mode 100644 index d1dc3ae..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.util.concurrent.ThreadFactory - -import org.slf4j.MDC - -object MdcThreadFactory { - def from(orig: ThreadFactory): ThreadFactory = new MdcThreadFactory(orig) -} - -class MdcThreadFactory(orig: ThreadFactory) extends ThreadFactory { - - override def newThread(runnable: Runnable): Thread = { - val parentMdcContext = MDC.getCopyOfContextMap - - orig.newThread(new Runnable { - def run(): Unit = { - val saveMdcContext = MDC.getCopyOfContextMap - setContextMap(parentMdcContext) - - try { - runnable.run() - } finally { - setContextMap(saveMdcContext) - } - } - }) - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala deleted file mode 100644 index 2f7fe6c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala +++ /dev/null @@ -1,60 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Dependency -import xyz.driver.pdsuicommon.concurrent.SafeBridgeUploadQueue.{DependencyResolver, SafeTask, Tag} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.serialization.Marshaller - -import scala.concurrent.{ExecutionContext, Future} - -object SafeBridgeUploadQueue { - - trait Tag extends Product with Serializable - - final case class SafeTask[T <: Tag](tag: T, private[SafeBridgeUploadQueue] val queueItem: BridgeUploadQueue.Item) - - object SafeTask { - implicit def toPhiString[T <: Tag](x: SafeTask[T]): PhiString = { - import x._ - phi"SafeTask(tag=${Unsafe(tag)}, $queueItem)" - } - } - - trait DependencyResolver[T <: Tag] { - def getDependency(tag: T): Option[Dependency] - } - -} - -class SafeBridgeUploadQueue[T <: Tag](kind: String, origQueue: BridgeUploadQueue)( - implicit tagMarshaller: Marshaller[T, String], - dependencyResolver: DependencyResolver[T], - executionContext: ExecutionContext) { - - type Task = SafeTask[T] - - def add(tag: T): Future[BridgeUploadQueue.Item] = - origQueue.add( - BridgeUploadQueue.Item( - kind = kind, - tag = tagMarshaller.write(tag), - dependency = dependencyResolver.getDependency(tag) - )) - - def tryRetry(task: Task): Future[Option[Task]] = wrap(origQueue.tryRetry(task.queueItem)) - - def get: Future[Option[Task]] = wrap(origQueue.get(kind)) - - def complete(tag: T): Future[Unit] = origQueue.complete(kind, tagMarshaller.write(tag)) - - private def wrap(x: Future[Option[BridgeUploadQueue.Item]]): Future[Option[Task]] = x.map(_.map(cover)) - - private def cover(rawTask: BridgeUploadQueue.Item): Task = { - val tag = tagMarshaller - .read(rawTask.tag) - .getOrElse(throw new IllegalArgumentException(s"Can not parse tag '${rawTask.tag}'")) - - SafeTask(tag, rawTask) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala deleted file mode 100644 index 7c290d1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import scala.concurrent.Future - -/** - * Where queries should run - */ -trait DbIo { - def runAsync[T](f: => T): Future[T] - def runSync[T](f: => T): T = f - def runAsyncTx[T](f: => T): Future[T] - def runSyncTx[T](f: => T): Unit -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala deleted file mode 100644 index d765833..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala +++ /dev/null @@ -1,10 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.domain.Id - -class EntityNotFoundException(id: String, tableName: String) - extends RuntimeException(s"Entity with id $id is not found in $tableName table") { - - def this(id: Id[_], tableName: String) = this(id.toString, tableName) - def this(id: Long, tableName: String) = this(id.toString, tableName) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala deleted file mode 100644 index 44f177c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -import scala.concurrent.Future -import scala.util.{Failure, Success, Try} - -class JdbcDbIo(sqlContext: TransactionalContext) extends DbIo with PhiLogging { - - override def runAsync[T](f: => T): Future[T] = { - Future(f)(sqlContext.executionContext) - } - - override def runAsyncTx[T](f: => T): Future[T] = { - import sqlContext.executionContext - - Future(sqlContext.transaction(f)).andThen { - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } - - override def runSyncTx[T](f: => T): Unit = { - Try(sqlContext.transaction(f)) match { - case Success(_) => - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala deleted file mode 100644 index 92689dd..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala +++ /dev/null @@ -1,19 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -/** - * @param pageNumber Starts with 1 - */ -final case class Pagination(pageSize: Int, pageNumber: Int) - -object Pagination { - - // @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-CommonRequestQueryParametersForWebServices - val Default = Pagination(pageSize = 100, pageNumber = 1) - - implicit def toPhiString(x: Pagination): PhiString = { - import x._ - phi"Pagination(pageSize=${Unsafe(pageSize)}, pageNumber=${Unsafe(pageNumber)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala deleted file mode 100644 index 0577921..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala +++ /dev/null @@ -1,208 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -sealed trait SearchFilterExpr { - def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] - def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr -} - -object SearchFilterExpr { - - val Empty = Intersection.Empty - val Forbid = Atom.Binary( - dimension = Dimension(None, "true"), - op = SearchFilterBinaryOperation.Eq, - value = "false" - ) - - final case class Dimension(tableName: Option[String], name: String) { - def isForeign: Boolean = tableName.isDefined - } - - sealed trait Atom extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - object Atom { - final case class Binary(dimension: Dimension, op: SearchFilterBinaryOperation, value: AnyRef) extends Atom - object Binary { - def apply(field: String, op: SearchFilterBinaryOperation, value: AnyRef): Binary = - Binary(Dimension(None, field), op, value) - } - - final case class NAry(dimension: Dimension, op: SearchFilterNAryOperation, values: Seq[AnyRef]) extends Atom - object NAry { - def apply(field: String, op: SearchFilterNAryOperation, values: Seq[AnyRef]): NAry = - NAry(Dimension(None, field), op, values) - } - - /** dimension.tableName extractor */ - object TableName { - def unapply(value: Atom): Option[String] = value match { - case Binary(Dimension(tableNameOpt, _), _, _) => tableNameOpt - case NAry(Dimension(tableNameOpt, _), _, _) => tableNameOpt - } - } - } - - final case class Intersection private (operands: Seq[SearchFilterExpr]) - extends SearchFilterExpr with SearchFilterExprSeqOps { - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else { - this.copy(operands.map(_.replace(f))) - } - } - - } - - object Intersection { - - val Empty = Intersection(Seq()) - - def create(operands: SearchFilterExpr*): SearchFilterExpr = { - val filtered = operands.filterNot(SearchFilterExpr.isEmpty) - filtered.size match { - case 0 => Empty - case 1 => filtered.head - case _ => Intersection(filtered) - } - } - } - - final case class Union private (operands: Seq[SearchFilterExpr]) - extends SearchFilterExpr with SearchFilterExprSeqOps { - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else { - this.copy(operands.map(_.replace(f))) - } - } - - } - - object Union { - - val Empty = Union(Seq()) - - def create(operands: SearchFilterExpr*): SearchFilterExpr = { - val filtered = operands.filterNot(SearchFilterExpr.isEmpty) - filtered.size match { - case 0 => Empty - case 1 => filtered.head - case _ => Union(filtered) - } - } - - def create(dimension: Dimension, values: String*): SearchFilterExpr = values.size match { - case 0 => SearchFilterExpr.Empty - case 1 => SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, values.head) - case _ => - val filters = values.map { value => - SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, value) - } - - create(filters: _*) - } - - def create(dimension: Dimension, values: Set[String]): SearchFilterExpr = - create(dimension, values.toSeq: _*) - - // Backwards compatible API - - /** Create SearchFilterExpr with empty tableName */ - def create(field: String, values: String*): SearchFilterExpr = - create(Dimension(None, field), values: _*) - - /** Create SearchFilterExpr with empty tableName */ - def create(field: String, values: Set[String]): SearchFilterExpr = - create(Dimension(None, field), values) - } - - case object AllowAll extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - case object DenyAll extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - def isEmpty(expr: SearchFilterExpr): Boolean = { - expr == Intersection.Empty || expr == Union.Empty - } - - sealed trait SearchFilterExprSeqOps { this: SearchFilterExpr => - - val operands: Seq[SearchFilterExpr] - - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else { - // Search the first expr among operands, which satisfy p - // Is's ok to use foldLeft. If there will be performance issues, replace it by recursive loop - operands.foldLeft(Option.empty[SearchFilterExpr]) { - case (None, expr) => expr.find(p) - case (x, _) => x - } - } - } - - } - - // There is no case, when this is unsafe. At this time. - implicit def toPhiString(x: SearchFilterExpr): PhiString = { - if (isEmpty(x)) Unsafe("SearchFilterExpr.Empty") - else Unsafe(x.toString) - } - -} - -sealed trait SearchFilterBinaryOperation - -object SearchFilterBinaryOperation { - - case object Eq extends SearchFilterBinaryOperation - case object NotEq extends SearchFilterBinaryOperation - case object Like extends SearchFilterBinaryOperation - case object Gt extends SearchFilterBinaryOperation - case object GtEq extends SearchFilterBinaryOperation - case object Lt extends SearchFilterBinaryOperation - case object LtEq extends SearchFilterBinaryOperation - -} - -sealed trait SearchFilterNAryOperation - -object SearchFilterNAryOperation { - - case object In extends SearchFilterNAryOperation - case object NotIn extends SearchFilterNAryOperation - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala deleted file mode 100644 index a56ab9a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala +++ /dev/null @@ -1,115 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import java.time.{LocalDateTime, ZoneOffset} - -import slick.jdbc.{JdbcProfile, GetResult} -import xyz.driver.core.database.SlickDal -import xyz.driver.pdsuicommon.logging._ - -import scala.collection.breakOut -import scala.concurrent.ExecutionContext - -object SlickPostgresQueryBuilder extends PhiLogging { - - import xyz.driver.pdsuicommon.db.SlickQueryBuilder._ - - def apply[T](databaseName: String, - tableName: String, - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink], - runner: Runner[T], - countRunner: CountRunner)(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - val parameters = SlickPostgresQueryBuilderParameters( - databaseName = databaseName, - tableData = TableData(tableName, lastUpdateFieldName, nullableFields), - links = links.map(x => x.foreignTableName -> x)(breakOut) - ) - new SlickPostgresQueryBuilder[T](parameters)(runner, countRunner) - } - - def apply[T](databaseName: String, - tableName: String, - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink])(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - apply[T](databaseName, - tableName, - SlickQueryBuilderParameters.AllFields, - lastUpdateFieldName, - nullableFields, - links) - } - - def apply[T](databaseName: String, - tableName: String, - fields: Set[String], - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink])(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - - val runner: Runner[T] = { parameters => - val sql = parameters.toSql(countQuery = false, fields = fields).as[T] - logger.debug(phi"${Unsafe(sql)}") - sqlContext.execute(sql) - } - - val countRunner: CountRunner = { parameters => - implicit val getCountResult: GetResult[(Int, Option[LocalDateTime])] = GetResult({ r => - val count = r.rs.getInt(1) - val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { - Option(r.rs.getTimestamp(2)).map(timestampToLocalDateTime) - } else None - (count, lastUpdate) - }) - val sql = parameters.toSql(countQuery = true).as[(Int, Option[LocalDateTime])] - logger.debug(phi"${Unsafe(sql)}") - sqlContext.execute(sql).map(_.head) - } - - apply[T]( - databaseName = databaseName, - tableName = tableName, - lastUpdateFieldName = lastUpdateFieldName, - nullableFields = nullableFields, - links = links, - runner = runner, - countRunner = countRunner - ) - } - - def timestampToLocalDateTime(timestamp: java.sql.Timestamp): LocalDateTime = { - LocalDateTime.ofInstant(timestamp.toInstant, ZoneOffset.UTC) - } -} - -class SlickPostgresQueryBuilder[T](parameters: SlickPostgresQueryBuilderParameters)( - implicit runner: SlickQueryBuilder.Runner[T], - countRunner: SlickQueryBuilder.CountRunner) - extends SlickQueryBuilder[T](parameters) { - - def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(filter = newFilter)) - } - - def withSorting(newSorting: Sorting): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(sorting = newSorting)) - } - - def withPagination(newPagination: Pagination): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(pagination = Some(newPagination))) - } - - def resetPagination: SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(pagination = None)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala deleted file mode 100644 index 9962edf..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala +++ /dev/null @@ -1,387 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import java.sql.{JDBCType, PreparedStatement} -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} - -object SlickQueryBuilder { - - type Runner[T] = SlickQueryBuilderParameters => Future[Seq[T]] - - type CountResult = Future[(Int, Option[LocalDateTime])] - - type CountRunner = SlickQueryBuilderParameters => CountResult - - /** - * Binder for PreparedStatement - */ - type Binder = PreparedStatement => PreparedStatement - - final case class TableData(tableName: String, - lastUpdateFieldName: Option[String] = None, - nullableFields: Set[String] = Set.empty) - - val AllFields = Set("*") - - implicit class SQLActionBuilderConcat(a: SQLActionBuilder) { - def concat(b: SQLActionBuilder): SQLActionBuilder = { - SQLActionBuilder(a.queryParts ++ b.queryParts, new SetParameter[Unit] { - def apply(p: Unit, pp: PositionedParameters): Unit = { - a.unitPConv.apply(p, pp) - b.unitPConv.apply(p, pp) - } - }) - } - } - - implicit object SetQueryParameter extends SetParameter[AnyRef] { - def apply(v: AnyRef, pp: PositionedParameters) = { - 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) - -object SlickQueryBuilderParameters { - val AllFields = Set("*") -} - -sealed trait SlickQueryBuilderParameters { - import SlickQueryBuilder._ - - def databaseName: String - def tableData: SlickQueryBuilder.TableData - def links: Map[String, SlickTableLink] - def filter: SearchFilterExpr - def sorting: Sorting - def pagination: Option[Pagination] - - def qs: String - - def findLink(tableName: String): SlickTableLink = links.get(tableName) match { - case None => throw new IllegalArgumentException(s"Cannot find a link for `$tableName`") - case Some(link) => link - } - - def toSql(countQuery: Boolean = false)(implicit profile: JdbcProfile): SQLActionBuilder = { - toSql(countQuery, SlickQueryBuilderParameters.AllFields) - } - - def toSql(countQuery: Boolean, fields: Set[String])(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - val escapedTableName = s"""$qs$databaseName$qs.$qs${tableData.tableName}$qs""" - val fieldsSql: String = if (countQuery) { - val suffix: String = tableData.lastUpdateFieldName match { - case Some(lastUpdateField) => s", max($escapedTableName.$qs$lastUpdateField$qs)" - case None => "" - } - s"count(*) $suffix" - } else { - if (fields == SlickQueryBuilderParameters.AllFields) { - s"$escapedTableName.*" - } else { - fields - .map { field => - s"$escapedTableName.$qs$field$qs" - } - .mkString(", ") - } - } - val where = filterToSql(escapedTableName, filter) - val orderBy = sortingToSql(escapedTableName, sorting) - - val limitSql = limitToSql() - - val sql = sql"""select #$fieldsSql from #$escapedTableName""" - - val filtersTableLinks: Seq[SlickTableLink] = { - import SearchFilterExpr._ - def aux(expr: SearchFilterExpr): Seq[SlickTableLink] = expr match { - case Atom.TableName(tableName) => List(findLink(tableName)) - case Intersection(xs) => xs.flatMap(aux) - case Union(xs) => xs.flatMap(aux) - case _ => Nil - } - aux(filter) - } - - val sortingTableLinks: Seq[SlickTableLink] = Sorting.collect(sorting) { - case Dimension(Some(foreignTableName), _, _) => findLink(foreignTableName) - } - - // Combine links from sorting and filter without duplicates - val foreignTableLinks = (filtersTableLinks ++ sortingTableLinks).distinct - - def fkSql(fkLinksSql: SQLActionBuilder, tableLinks: Seq[SlickTableLink]): SQLActionBuilder = { - if (tableLinks.nonEmpty) { - tableLinks.head match { - case SlickTableLink(keyColumnName, foreignTableName, foreignKeyColumnName) => - val escapedForeignTableName = s"$qs$databaseName$qs.$qs$foreignTableName$qs" - val join = sql""" inner join #$escapedForeignTableName - on #$escapedTableName.#$qs#$keyColumnName#$qs=#$escapedForeignTableName.#$qs#$foreignKeyColumnName#$qs""" - fkSql(fkLinksSql concat join, tableLinks.tail) - } - } else fkLinksSql - } - val foreignTableLinksSql = fkSql(sql"", foreignTableLinks) - - val whereSql = if (where.queryParts.size > 1) { - sql" where " concat where - } else sql"" - - val orderSql = if (orderBy.nonEmpty && !countQuery) { - sql" order by #$orderBy" - } else sql"" - - val limSql = if (limitSql.queryParts.size > 1 && !countQuery) { - sql" " concat limitSql - } else sql"" - - sql concat foreignTableLinksSql concat whereSql concat orderSql concat limSql - } - - /** - * Converts filter expression to SQL expression. - * - * @return Returns SQL string and list of values for binding in prepared statement. - */ - protected def filterToSql(escapedTableName: String, filter: SearchFilterExpr)( - implicit profile: JdbcProfile): SQLActionBuilder = { - import SearchFilterBinaryOperation._ - import SearchFilterExpr._ - import profile.api._ - - def isNull(string: AnyRef) = Option(string).isEmpty || string.toString.toLowerCase == "null" - - def escapeDimension(dimension: SearchFilterExpr.Dimension) = { - 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 { - case x if !SearchFilterExpr.isEmpty(x) => filterToSql(escapedTableName, x) - } - - def multipleSqlToAction(first: Boolean, - op: String, - conditions: Seq[SQLActionBuilder], - sql: SQLActionBuilder): SQLActionBuilder = { - if (conditions.nonEmpty) { - val condition = conditions.head - if (first) { - multipleSqlToAction(first = false, op, conditions.tail, condition) - } else { - multipleSqlToAction(first = false, op, conditions.tail, sql concat sql" #${op} " concat condition) - } - } else sql - } - - def concatenateParameters(sql: SQLActionBuilder, first: Boolean, tail: Seq[AnyRef]): SQLActionBuilder = { - if (tail.nonEmpty) { - if (!first) { - concatenateParameters(sql concat sql""",${tail.head}""", first = false, tail.tail) - } else { - concatenateParameters(sql"""(${tail.head}""", first = false, tail.tail) - } - } else sql concat sql")" - } - - filter match { - case x if isEmpty(x) => - sql"" - - case AllowAll => - sql"1=1" - - case DenyAll => - sql"1=0" - - case Atom.Binary(dimension, Eq, value) if isNull(value) => - sql"#${escapeDimension(dimension)} is NULL" - - case Atom.Binary(dimension, NotEq, value) if isNull(value) => - sql"#${escapeDimension(dimension)} is not NULL" - - case Atom.Binary(dimension, NotEq, value) if tableData.nullableFields.contains(dimension.name) => - // In MySQL NULL <> Any === NULL - // So, to handle NotEq for nullable fields we need to use more complex SQL expression. - // http://dev.mysql.com/doc/refman/5.7/en/working-with-null.html - val escapedColumn = escapeDimension(dimension) - sql"(#${escapedColumn} is null or #${escapedColumn} != $value)" - - case Atom.Binary(dimension, op, value) => - val operator = op match { - case Eq => sql"=" - case NotEq => sql"!=" - case Like => sql" like " - case Gt => sql">" - case GtEq => sql">=" - case Lt => sql"<" - case LtEq => sql"<=" - } - sql"#${escapeDimension(dimension)}" concat operator concat sql"""$value""" - - case Atom.NAry(dimension, op, values) => - val sqlOp = op match { - case SearchFilterNAryOperation.In => sql" in " - case SearchFilterNAryOperation.NotIn => sql" not in " - } - - 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(first = true, "and", filterToSqlMultiple(operands), sql"") - sql"(" concat filter concat sql")" - - case Union(operands) => - val filter = multipleSqlToAction(first = true, "or", filterToSqlMultiple(operands), sql"") - sql"(" concat filter concat sql")" - } - } - - protected def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder - - /** - * @param escapedMainTableName Should be escaped - */ - protected def sortingToSql(escapedMainTableName: String, sorting: Sorting)(implicit profile: JdbcProfile): String = { - sorting match { - case Dimension(optSortingTableName, field, order) => - val sortingTableName = - optSortingTableName.map(x => s"$qs$databaseName$qs.$qs$x$qs").getOrElse(escapedMainTableName) - val fullName = s"$sortingTableName.$qs$field$qs" - - s"$fullName ${orderToSql(order)}" - - case Sequential(xs) => - xs.map(sortingToSql(escapedMainTableName, _)).mkString(", ") - } - } - - protected def orderToSql(x: SortingOrder): String = x match { - case Ascending => "asc" - case Descending => "desc" - } - - protected def binder(bindings: List[AnyRef])(bind: PreparedStatement): PreparedStatement = { - bindings.zipWithIndex.foreach { - case (binding, index) => - bind.setObject(index + 1, binding) - } - - bind - } - -} - -final case class SlickPostgresQueryBuilderParameters(databaseName: String, - tableData: SlickQueryBuilder.TableData, - links: Map[String, SlickTableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) - extends SlickQueryBuilderParameters { - - def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - pagination.map { pagination => - val startFrom = (pagination.pageNumber - 1) * pagination.pageSize - sql"limit #${pagination.pageSize} OFFSET #$startFrom" - } getOrElse (sql"") - } - - val qs = """"""" - -} - -/** - * @param links Links to another tables grouped by foreignTableName - */ -final case class SlickMysqlQueryBuilderParameters(databaseName: String, - tableData: SlickQueryBuilder.TableData, - links: Map[String, SlickTableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) - extends SlickQueryBuilderParameters { - - def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - pagination - .map { pagination => - val startFrom = (pagination.pageNumber - 1) * pagination.pageSize - sql"limit #$startFrom, #${pagination.pageSize}" - } - .getOrElse(sql"") - } - - val qs = """`""" - -} - -abstract class SlickQueryBuilder[T](val parameters: SlickQueryBuilderParameters)( - implicit runner: SlickQueryBuilder.Runner[T], - countRunner: SlickQueryBuilder.CountRunner) { - - def run()(implicit ec: ExecutionContext): Future[Seq[T]] = runner(parameters) - - def runCount()(implicit ec: ExecutionContext): SlickQueryBuilder.CountResult = countRunner(parameters) - - /** - * Runs the query and returns total found rows without considering of pagination. - */ - def runWithCount()(implicit ec: ExecutionContext): Future[(Seq[T], Int, Option[LocalDateTime])] = { - for { - all <- run - (total, lastUpdate) <- runCount - } yield (all, total, lastUpdate) - } - - def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] - - def withFilter(filter: Option[SearchFilterExpr]): SlickQueryBuilder[T] = { - filter.fold(this)(withFilter) - } - - def resetFilter: SlickQueryBuilder[T] = withFilter(SearchFilterExpr.Empty) - - def withSorting(newSorting: Sorting): SlickQueryBuilder[T] - - def withSorting(sorting: Option[Sorting]): SlickQueryBuilder[T] = { - sorting.fold(this)(withSorting) - } - - def resetSorting: SlickQueryBuilder[T] = withSorting(Sorting.Empty) - - def withPagination(newPagination: Pagination): SlickQueryBuilder[T] - - def withPagination(pagination: Option[Pagination]): SlickQueryBuilder[T] = { - pagination.fold(this)(withPagination) - } - - def resetPagination: SlickQueryBuilder[T] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala deleted file mode 100644 index 8adf629..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala +++ /dev/null @@ -1,61 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -import scala.collection.generic.CanBuildFrom - -sealed trait SortingOrder -object SortingOrder { - - case object Ascending extends SortingOrder - case object Descending extends SortingOrder - -} - -sealed trait Sorting - -object Sorting { - - val Empty = Sequential(Seq.empty) - - /** - * @param tableName None if the table is default (same) - * @param name Dimension name - * @param order Order - */ - final case class Dimension(tableName: Option[String], name: String, order: SortingOrder) extends Sorting { - def isForeign: Boolean = tableName.isDefined - } - - final case class Sequential(sorting: Seq[Dimension]) extends Sorting { - override def toString: String = if (isEmpty(this)) "Empty" else super.toString - } - - def isEmpty(input: Sorting): Boolean = { - input match { - case Sequential(Seq()) => true - case _ => false - } - } - - def filter(sorting: Sorting, p: Dimension => Boolean): Seq[Dimension] = sorting match { - case x: Dimension if p(x) => Seq(x) - case _: Dimension => Seq.empty - case Sequential(xs) => xs.filter(p) - } - - def collect[B, That](sorting: Sorting)(f: PartialFunction[Dimension, B])( - implicit bf: CanBuildFrom[Seq[Dimension], B, That]): That = sorting match { - case x: Dimension if f.isDefinedAt(x) => - val r = bf.apply() - r += f(x) - r.result() - - case _: Dimension => bf.apply().result() - case Sequential(xs) => xs.collect(f) - } - - // Contains dimensions and ordering only, thus it is safe. - implicit def toPhiString(x: Sorting): PhiString = Unsafe(x.toString) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala deleted file mode 100644 index 9883b9e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala +++ /dev/null @@ -1,11 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import scala.concurrent.ExecutionContext - -trait TransactionalContext { - - implicit def executionContext: ExecutionContext - - def transaction[T](f: => T): T - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala deleted file mode 100644 index e62238e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.db.repositories - -trait Repository extends RepositoryLogging diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala deleted file mode 100644 index d1ec1da..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala +++ /dev/null @@ -1,62 +0,0 @@ -package xyz.driver.pdsuicommon.db.repositories - -import xyz.driver.pdsuicommon.logging._ - -trait RepositoryLogging extends PhiLogging { - - protected def logCreatedOne[T](x: T)(implicit toPhiString: T => PhiString): T = { - logger.info(phi"An entity was created: $x") - x - } - - protected def logCreatedMultiple[T <: Iterable[_]](xs: T)(implicit toPhiString: T => PhiString): T = { - if (xs.nonEmpty) { - logger.info(phi"Entities were created: $xs") - } - xs - } - - protected def logUpdatedOne(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity is up to date") - case 1 => logger.info(phi"The entity was updated") - case x => logger.warn(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logUpdatedOneUnimportant(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity is up to date") - case 1 => logger.trace(phi"The entity was updated") - case x => logger.warn(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logUpdatedMultiple(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"All entities are up to date") - case x => logger.info(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logDeletedOne(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity does not exist") - case 1 => logger.info(phi"The entity was deleted") - case x => logger.warn(phi"Deleted ${Unsafe(x)} entities, expected one") - } - rowsAffected - } - - protected def logDeletedMultiple(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"Entities do not exist") - case x => logger.info(phi"Deleted ${Unsafe(x)} entities") - } - rowsAffected - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala deleted file mode 100644 index e238245..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala +++ /dev/null @@ -1,51 +0,0 @@ -package xyz.driver.pdsuicommon.domain - -import java.util.UUID - -import xyz.driver.pdsuicommon.logging._ - -sealed trait Id[+T] - -final case class CompoundId[Id1 <: Id[_], Id2 <: Id[_]](part1: Id1, part2: Id2) extends Id[(Id1, Id2)] - -final case class LongId[+T](id: Long) extends Id[T] { - override def toString: String = id.toString - - def is(longId: Long): Boolean = { - id == longId - } -} - -object LongId { - implicit def toPhiString[T](x: LongId[T]): PhiString = Unsafe(s"LongId(${x.id})") -} - -final case class StringId[+T](id: String) extends Id[T] { - override def toString: String = id - - def is(stringId: String): Boolean = { - id == stringId - } -} - -object StringId { - implicit def toPhiString[T](x: StringId[T]): PhiString = Unsafe(s"StringId(${x.id})") -} - -final case class UuidId[+T](id: UUID) extends Id[T] { - override def toString: String = id.toString -} - -object UuidId { - - /** - * @note May fail, if `string` is invalid UUID. - */ - def apply[T](string: String): UuidId[T] = new UuidId[T](UUID.fromString(string)) - - def apply[T](): UuidId[T] = new UuidId[T](UUID.randomUUID()) - - implicit def ordering[T] = Ordering.by[UuidId[T], String](_.toString) - - implicit def toPhiString[T](x: UuidId[T]): PhiString = Unsafe(s"UuidId(${x.id})") -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala deleted file mode 100644 index ee4d884..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.domain - -import xyz.driver.pdsuicommon.logging._ - -final case class TextJson[+T](content: T) { - def map[U](f: T => U): TextJson[U] = copy(f(content)) -} - -object TextJson { - - implicit def toPhiString[T](x: TextJson[T])(implicit inner: T => PhiString): PhiString = { - phi"TextJson(${x.content})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala deleted file mode 100644 index becb585..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.pdsuicommon.logging.{PhiString, Unsafe} -import xyz.driver.pdsuicommon.utils.Utils - -trait DomainError { - - protected def userMessage: String - - def getMessage: String = userMessage - -} - -object DomainError { - - // 404 error - trait NotFoundError extends DomainError - - // 403 error - trait AuthorizationError extends DomainError - - implicit def toPhiString(x: DomainError): PhiString = { - // userMessage possibly can contain a personal information, - // so we should prevent it to be printed in logs. - Unsafe(Utils.getClassSimpleName(x.getClass)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala deleted file mode 100644 index 748e76a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.core.json.EnumJsonFormat - -@SuppressWarnings(Array("org.wartremover.warts.Enumeration")) -object ErrorCode extends Enumeration { - - type ErrorCode = Value - val Unspecified = Value(1) - - implicit val jsonFormat = new EnumJsonFormat[ErrorCode]( - "200" -> ErrorCode.Value(200), - "400" -> ErrorCode.Value(400), - "401" -> ErrorCode.Value(401), - "403" -> ErrorCode.Value(403), - "404" -> ErrorCode.Value(404), - "500" -> ErrorCode.Value(500) - ) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala deleted file mode 100644 index 4d6aa0b..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala +++ /dev/null @@ -1,52 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import spray.json._ -import ErrorsResponse.ResponseError - -final case class ErrorsResponse(errors: Seq[ResponseError], requestId: String) - -object ErrorsResponse { - import DefaultJsonProtocol._ - - /** - * @param data Any data that can be associated with particular error.Ex.: error field name - * @param message Error message - * @param code Unique error code - * - * @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-HTTPStatuscodes - */ - final case class ResponseError(data: Option[String], message: String, code: Int) - - object ResponseError { - - implicit val responseErrorJsonFormat: RootJsonFormat[ResponseError] = jsonFormat3(ResponseError.apply) - - } - - implicit val errorsResponseJsonFormat: RootJsonFormat[ErrorsResponse] = new RootJsonFormat[ErrorsResponse] { - override def write(obj: ErrorsResponse): JsValue = { - JsObject( - "errors" -> obj.errors.map(_.toJson).toJson, - "requestId" -> obj.requestId.toJson - ) - } - - override def read(json: JsValue): ErrorsResponse = json match { - case JsObject(fields) => - val errors = fields - .get("errors") - .map(_.convertTo[Seq[ResponseError]]) - .getOrElse(deserializationError(s"ErrorsResponse json object does not contain `errors` field: $json")) - - val requestId = fields - .get("requestId") - .map(id => id.convertTo[String]) - .getOrElse(deserializationError(s"ErrorsResponse json object does not contain `requestId` field: $json")) - - ErrorsResponse(errors, requestId) - - case _ => deserializationError(s"Expected json as ErrorsResponse, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala deleted file mode 100644 index c9578b3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala +++ /dev/null @@ -1,18 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import java.io.{ByteArrayOutputStream, PrintStream} - -object ExceptionFormatter { - - def format(e: Throwable): String = s"$e\n${printStackTrace(e)}" - - def printStackTrace(e: Throwable): String = { - val baos = new ByteArrayOutputStream() - val ps = new PrintStream(baos) - - e.printStackTrace(ps) - - ps.close() - baos.toString() - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala deleted file mode 100644 index 7137255..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala +++ /dev/null @@ -1,5 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.pdsuicommon.validation.ValidationError - -class FailedValidationException(val error: ValidationError) extends RuntimeException("The validation is failed") diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala deleted file mode 100644 index 5705229..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.error - -final case class IncorrectIdException(message: String) extends Exception(message) diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala deleted file mode 100644 index 085dcd8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala +++ /dev/null @@ -1,90 +0,0 @@ -package xyz.driver.pdsuicommon.http - -import java.io.Closeable -import java.net.URL -import java.util.concurrent.{ExecutorService, Executors} - -import com.typesafe.scalalogging.StrictLogging -import org.asynchttpclient._ -import org.slf4j.MDC -import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory -import xyz.driver.pdsuicommon.utils.RandomUtils - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future, Promise} - -class AsyncHttpClientFetcher(settings: AsyncHttpClientFetcher.Settings) - extends HttpFetcher with Closeable with StrictLogging { - - private val es: ExecutorService = { - val threadFactory = MdcThreadFactory.from(Executors.defaultThreadFactory()) - Executors.newSingleThreadExecutor(threadFactory) - } - - private implicit val executionContext = ExecutionContext.fromExecutor(es) - - private def httpClientConfig: DefaultAsyncHttpClientConfig = { - val builder = new DefaultAsyncHttpClientConfig.Builder() - builder.setConnectTimeout(settings.connectTimeout.toMillis.toInt) - builder.setReadTimeout(settings.readTimeout.toMillis.toInt) - // builder.setThreadFactory(threadFactory) // Doesn't help to push MDC context into AsyncCompletionHandler - builder.build() - } - - private val httpClient = new DefaultAsyncHttpClient(httpClientConfig) - - override def apply(url: URL): Future[Array[Byte]] = { - val fingerPrint = RandomUtils.randomString(10) - - // log all outcome connections - logger.info("{}, apply({})", fingerPrint, url) - val promise = Promise[Response]() - - httpClient - .prepareGet(url.toString) - .execute(new AsyncCompletionHandler[Response] { - override def onCompleted(response: Response): Response = { - promise.success(response) - response - } - - override def onThrowable(t: Throwable): Unit = { - promise.failure(t) - super.onThrowable(t) - } - }) - - // Promises have their own ExecutionContext - // So, we have to hack it. - val parentMdcContext = MDC.getCopyOfContextMap - promise.future.flatMap { response => - setContextMap(parentMdcContext) - - if (response.getStatusCode == 200) { - // DO NOT LOG body, it could be PHI - val bytes = response.getResponseBodyAsBytes - logger.debug("{}, size is {}B", fingerPrint, bytes.size.asInstanceOf[AnyRef]) - Future.successful(bytes) - } else { - logger.error("{}, HTTP {}", fingerPrint, response.getStatusCode.asInstanceOf[AnyRef]) - logger.trace(response.getResponseBody().take(100)) - Future.failed(new IllegalStateException("An unexpected response from the server")) - } - } - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - override def close(): Unit = { - httpClient.close() - es.shutdown() - } - -} - -object AsyncHttpClientFetcher { - - final case class Settings(connectTimeout: FiniteDuration, readTimeout: FiniteDuration) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala deleted file mode 100644 index d7bc3d3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala +++ /dev/null @@ -1,115 +0,0 @@ -package xyz.driver.pdsuicommon.http - -import java.io.Closeable -import java.net.URI -import java.util.concurrent.{ExecutorService, Executors} - -import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory -import xyz.driver.pdsuicommon.http.AsyncHttpClientUploader._ -import xyz.driver.pdsuicommon.utils.RandomUtils -import com.typesafe.scalalogging.StrictLogging -import org.asynchttpclient._ -import org.slf4j.MDC - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future, Promise} - -class AsyncHttpClientUploader(settings: Settings) extends Closeable with StrictLogging { - - private val es: ExecutorService = { - val threadFactory = MdcThreadFactory.from(Executors.defaultThreadFactory()) - Executors.newSingleThreadExecutor(threadFactory) - } - - private implicit val executionContext = ExecutionContext.fromExecutor(es) - - private def httpClientConfig: DefaultAsyncHttpClientConfig = { - val builder = new DefaultAsyncHttpClientConfig.Builder() - builder.setConnectTimeout(settings.connectTimeout.toMillis.toInt) - builder.setRequestTimeout(settings.requestTimeout.toMillis.toInt) - // builder.setThreadFactory(threadFactory) // Doesn't help to push MDC context into AsyncCompletionHandler - builder.build() - } - - private val httpClient = new DefaultAsyncHttpClient(httpClientConfig) - - def run(method: Method, uri: URI, contentType: String, data: String): Future[Unit] = { - // log all outcome connections - val fingerPrint = RandomUtils.randomString(10) - logger.info("{}, apply(method={}, uri={}, contentType={})", fingerPrint, method, uri, contentType) - val promise = Promise[Response]() - - val q = new RequestBuilder(method.toString) - .setUrl(uri.toString) - .setBody(data) - - settings.defaultHeaders.foreach { - case (k, v) => - q.setHeader(k, v) - } - - q.addHeader("Content-Type", contentType) - - httpClient - .prepareRequest(q) - .execute(new AsyncCompletionHandler[Unit] { - override def onCompleted(response: Response): Unit = { - promise.success(response) - } - - override def onThrowable(t: Throwable): Unit = { - promise.failure(t) - super.onThrowable(t) - } - }) - - // see AsyncHttpClientFetcher - val parentMdcContext = MDC.getCopyOfContextMap - promise.future.flatMap { response => - setContextMap(parentMdcContext) - - val statusCode = response.getStatusCode - // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success - if (statusCode >= 200 && statusCode < 300) { - logger.debug("{}, success", fingerPrint) - Future.successful(()) - } else { - logger.error( - "{}, HTTP {}, BODY:\n{}", - fingerPrint, - response.getStatusCode.asInstanceOf[AnyRef], - response.getResponseBody.take(100) - ) - Future.failed(new IllegalStateException("An unexpected response from the server")) - } - } - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - override def close(): Unit = { - httpClient.close() - es.shutdown() - } -} - -object AsyncHttpClientUploader { - - final case class Settings(connectTimeout: FiniteDuration, - requestTimeout: FiniteDuration, - defaultHeaders: Map[String, String] = Map.empty) - - sealed trait Method - - object Method { - - case object Put extends Method { - override val toString = "PUT" - } - - case object Post extends Method { - override val toString = "POST" - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala deleted file mode 100644 index 46b86a6..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala +++ /dev/null @@ -1,114 +0,0 @@ -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.pdsuicommon.error._ -import xyz.driver.pdsuicommon.error.DomainError._ -import xyz.driver.pdsuicommon.error.ErrorsResponse.ResponseError -import xyz.driver.pdsuicommon.parsers._ -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain._ -import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ -import xyz.driver.core.generators -import xyz.driver.core.rest.ContextHeaders -import xyz.driver.core.rest.errors.{InvalidActionException, InvalidInputException, ResourceNotFoundException} - -import scala.util.control._ -import scala.util._ - -trait Directives { - - val paginated: Directive1[Pagination] = parameterSeq.flatMap { params => - PaginationParser.parse(params) match { - case Success(pagination) => provide(pagination) - case Failure(ex) => - reject(ValidationRejection("invalid pagination parameter", Some(ex))) - } - } - - def sorted(validDimensions: Set[String] = Set.empty): Directive1[Sorting] = parameterSeq.flatMap { params => - SortingParser.parse(validDimensions, params) match { - case Success(sorting) => provide(sorting) - case Failure(ex) => - reject(ValidationRejection("invalid sorting parameter", Some(ex))) - } - } - - val dimensioned: Directive1[Dimensions] = parameterSeq.flatMap { params => - DimensionsParser.tryParse(params) match { - case Success(dims) => provide(dims) - case Failure(ex) => - reject(ValidationRejection("invalid dimension parameter", Some(ex))) - } - } - - val searchFiltered: Directive1[SearchFilterExpr] = parameterSeq.flatMap { params => - SearchFilterParser.parse(params) match { - case Success(sorting) => provide(sorting) - case Failure(ex) => - reject(ValidationRejection("invalid filter parameter", Some(ex))) - } - } - - def StringIdInPath[T]: PathMatcher1[StringId[T]] = - PathMatchers.Segment.map((id) => StringId(id.toString)) - - def LongIdInPath[T]: PathMatcher1[LongId[T]] = - PathMatchers.LongNumber.map((id) => LongId(id)) - - def UuidIdInPath[T]: PathMatcher1[UuidId[T]] = - PathMatchers.JavaUUID.map((id) => UuidId(id)) - - def failFast[A](reply: A): A = reply match { - case err: NotFoundError => throw ResourceNotFoundException(err.getMessage) - case err: AuthorizationError => throw InvalidActionException(err.getMessage) - case err: DomainError => throw InvalidInputException(err.getMessage) - case other => other - } - - def domainExceptionHandler(req: String): ExceptionHandler = { - def errorResponse(msg: String, code: Int) = - ErrorsResponse(Seq(ResponseError(None, msg, code)), req) - ExceptionHandler { - case ex: InvalidActionException => - complete(StatusCodes.Forbidden -> errorResponse(ex.message, 403)) - - case ex: ResourceNotFoundException => - complete(StatusCodes.NotFound -> errorResponse(ex.message, 404)) - - case ex: InvalidInputException => - complete(StatusCodes.BadRequest -> errorResponse(ex.message, 400)) - - case NonFatal(ex) => - complete(StatusCodes.InternalServerError -> errorResponse(ex.getMessage, 500)) - } - } - - def domainRejectionHandler(req: String): RejectionHandler = { - def wrapContent(message: String) = { - import ErrorsResponse._ - val err: ErrorsResponse = ErrorsResponse(Seq(ResponseError(None, message, 1)), req) - val text = errorsResponseJsonFormat.write(err).toString() - HttpEntity(ContentTypes.`application/json`, text) - } - 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 - } - } - - val tracked: Directive1[String] = optionalHeaderValueByName(ContextHeaders.TrackingIdHeader) flatMap { - case Some(id) => provide(id) - case None => provide(generators.nextUuid().toString) - } - - val domainResponse: Directive0 = tracked.flatMap { id => - handleExceptions(domainExceptionHandler(id)) & handleRejections(domainRejectionHandler(id)) - } - -} - -object Directives extends Directives diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/package.scala b/src/main/scala/xyz/driver/pdsuicommon/http/package.scala deleted file mode 100644 index 20b1c97..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/package.scala +++ /dev/null @@ -1,9 +0,0 @@ -package xyz.driver.pdsuicommon - -import java.net.URL - -import scala.concurrent.Future - -package object http { - type HttpFetcher = URL => Future[Array[Byte]] -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala b/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala deleted file mode 100644 index 9383a1c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuicommon.json - -import java.text.SimpleDateFormat - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper} -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.scala.DefaultScalaModule -import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper - -object JsonSerializer { - - private val mapper = new ObjectMapper() with ScalaObjectMapper - mapper.registerModule(DefaultScalaModule) - mapper.registerModule(new JavaTimeModule) - mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")) - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - - def serialize(value: Any): String = { - mapper.writeValueAsString(value) - } - - def deserialize[T](value: String)(implicit m: Manifest[T]): T = { - mapper.readValue(value) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala deleted file mode 100644 index 045f37a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala +++ /dev/null @@ -1,17 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import org.slf4j.{Logger => Underlying} - -class DefaultPhiLogger private[logging] (underlying: Underlying) extends PhiLogger { - - def error(message: PhiString): Unit = underlying.error(message.text) - - def warn(message: PhiString): Unit = underlying.warn(message.text) - - def info(message: PhiString): Unit = underlying.info(message.text) - - def debug(message: PhiString): Unit = underlying.debug(message.text) - - def trace(message: PhiString): Unit = underlying.trace(message.text) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala deleted file mode 100644 index 109d52a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala +++ /dev/null @@ -1,62 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import java.io.File -import java.net.{URI, URL} -import java.nio.file.Path -import java.time.{LocalDate, LocalDateTime} -import java.util.UUID - -import scala.concurrent.duration.Duration - -trait Implicits { - - // DO NOT ADD! - // phi"$fullName" is easier to write, than phi"${Unsafe(fullName)}" - // If you wrote the second version, it means that you know, what you doing. - // implicit def toPhiString(s: String): PhiString = Unsafe(s) - - implicit def toPhiStringContext(sc: StringContext): PhiStringContext = new PhiStringContext(sc) - - implicit def booleanToPhiString(x: Boolean): PhiString = Unsafe(x.toString) - - implicit def uriToPhiString(x: URI): PhiString = Unsafe(x.toString) - - implicit def urlToPhiString(x: URL): PhiString = Unsafe(x.toString) - - implicit def pathToPhiString(x: Path): PhiString = Unsafe(x.toString) - - implicit def fileToPhiString(x: File): PhiString = Unsafe(x.toString) - - implicit def localDateTimeToPhiString(x: LocalDateTime): PhiString = Unsafe(x.toString) - - implicit def localDateToPhiString(x: LocalDate): PhiString = Unsafe(x.toString) - - implicit def durationToPhiString(x: Duration): PhiString = Unsafe(x.toString) - - implicit def uuidToPhiString(x: UUID): PhiString = Unsafe(x.toString) - - implicit def tuple2ToPhiString[T1, T2](x: (T1, T2))(implicit inner1: T1 => PhiString, - inner2: T2 => PhiString): PhiString = x match { - case (a, b) => phi"($a, $b)" - } - - implicit def tuple3ToPhiString[T1, T2, T3](x: (T1, T2, T3))(implicit inner1: T1 => PhiString, - inner2: T2 => PhiString, - inner3: T3 => PhiString): PhiString = x match { - case (a, b, c) => phi"($a, $b, $c)" - } - - implicit def optionToPhiString[T](opt: Option[T])(implicit inner: T => PhiString): PhiString = opt match { - case None => phi"None" - case Some(x) => phi"Some($x)" - } - - implicit def iterableToPhiString[T](xs: Iterable[T])(implicit inner: T => PhiString): PhiString = { - Unsafe(xs.map(inner(_).text).mkString("Col(", ", ", ")")) - } - - implicit def throwableToPhiString(x: Throwable): PhiString = { - Unsafe(Option(x.getMessage).getOrElse(x.getClass.getName)) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala deleted file mode 100644 index 741ef18..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -trait PhiLogger { - - def error(message: PhiString): Unit - - def warn(message: PhiString): Unit - - def info(message: PhiString): Unit - - def debug(message: PhiString): Unit - - def trace(message: PhiString): Unit - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala deleted file mode 100644 index e7730ea..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import org.slf4j.LoggerFactory - -trait PhiLogging extends Implicits { - - protected val logger: PhiLogger = new DefaultPhiLogger(LoggerFactory.getLogger(getClass.getName)) - - /** - * Logs the failMessage on an error level, if isSuccessful is false. - * @return isSuccessful - */ - protected def loggedError(isSuccessful: Boolean, failMessage: PhiString): Boolean = { - if (!isSuccessful) { - logger.error(failMessage) - } - isSuccessful - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala deleted file mode 100644 index 78ac62e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala +++ /dev/null @@ -1,6 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -class PhiString(private[logging] val text: String) { - // scalastyle:off - @inline def +(that: PhiString) = new PhiString(this.text + that.text) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala deleted file mode 100644 index 97819de..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala +++ /dev/null @@ -1,8 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -final class PhiStringContext(val sc: StringContext) extends AnyVal { - def phi(args: PhiString*): PhiString = { - val phiArgs = args.map(_.text) - new PhiString(sc.s(phiArgs: _*)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala deleted file mode 100644 index fbd17eb..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User - -object TimeLogger extends PhiLogging { - - def logTime(userId: xyz.driver.core.Id[User], label: String, obj: String): Unit = { - val now = LocalDateTime.now(ZoneId.of("Z")) - logger.info(phi"User id=${Unsafe(userId)} performed an action at ${Unsafe(label)}=$now with a ${Unsafe(obj)} ") - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala deleted file mode 100644 index c3ebe80..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala +++ /dev/null @@ -1,7 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -/** - * Use it with care! - */ -final case class Unsafe[T](private[logging] val value: T) - extends PhiString(Option(value).map(_.toString).getOrElse("<null>")) diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala deleted file mode 100644 index 2905108..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon - -package object logging extends Implicits diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala deleted file mode 100644 index 17c09ed..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala +++ /dev/null @@ -1,30 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import scala.util.{Failure, Success, Try} - -class Dimensions(private val xs: Set[String] = Set.empty) { - def contains(x: String): Boolean = xs.isEmpty || xs.contains(x) -} - -object DimensionsParser { - - @deprecated("play-akka transition", "0") - def tryParse(query: Map[String, Seq[String]]): Try[Dimensions] = - tryParse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def tryParse(query: Seq[(String, String)]): Try[Dimensions] = { - query.collect { case ("dimensions", value) => value } match { - case Nil => Success(new Dimensions()) - - case x +: Nil => - val raw: Set[String] = x.split(",").view.map(_.trim).filter(_.nonEmpty).to[Set] - Success(new Dimensions(raw)) - - case xs => - Failure(new IllegalArgumentException(s"Dimensions are specified ${xs.size} times")) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala deleted file mode 100644 index b59b1a5..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.db._ -import scala.util._ - -object PaginationParser { - - @deprecated("play-akka transition", "0") - def parse(query: Map[String, Seq[String]]): Try[Pagination] = - parse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(query: Seq[(String, String)]): Try[Pagination] = { - val IntString = """(\d+)""".r - def validate(field: String, default: Int) = query.collectFirst { case (`field`, size) => size } match { - case Some(IntString(x)) if x.toInt > 0 => x.toInt - case Some(IntString(x)) => throw new ParseQueryArgException((field, s"must greater than zero (found $x)")) - case Some(str) => throw new ParseQueryArgException((field, s"must be an integer (found $str)")) - case None => default - } - - Try { - Pagination(validate("pageSize", Pagination.Default.pageSize), - validate("pageNumber", Pagination.Default.pageNumber)) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala deleted file mode 100644 index 64b3d2e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -class ParseQueryArgException(val errors: (String, String)*) extends Exception(errors.mkString(",")) diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala deleted file mode 100644 index aeb6c16..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala +++ /dev/null @@ -1,178 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import java.util.UUID - -import xyz.driver.pdsuicommon.utils.Implicits.{toCharOps, toStringOps} -import fastparse.all._ -import fastparse.core.Parsed -import xyz.driver.pdsuicommon.db.{SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation} -import xyz.driver.pdsuicommon.utils.Utils._ - -import scala.util.Try - -@SuppressWarnings(Array("org.wartremover.warts.Product", "org.wartremover.warts.Serializable")) -object SearchFilterParser { - - private object BinaryAtomFromTuple { - def unapply(input: (SearchFilterExpr.Dimension, (String, Any))): Option[SearchFilterExpr.Atom.Binary] = { - val (dimensionName, (strOperation, value)) = input - val updatedValue = trimIfString(value) - - parseOperation(strOperation.toLowerCase).map { op => - SearchFilterExpr.Atom.Binary(dimensionName, op, updatedValue.asInstanceOf[AnyRef]) - } - } - } - - private object NAryAtomFromTuple { - // Compiler warning: unchecked since it is eliminated by erasure, if we user Seq[String] - def unapply(input: (SearchFilterExpr.Dimension, (String, Seq[_]))): Option[SearchFilterExpr.Atom.NAry] = { - val (dimensionName, (strOperation, xs)) = input - val updatedValues = xs.map(trimIfString) - - if (strOperation.toLowerCase == "in") { - Some( - SearchFilterExpr.Atom - .NAry(dimensionName, SearchFilterNAryOperation.In, updatedValues.map(_.asInstanceOf[AnyRef]))) - } else { - None - } - } - } - - private def trimIfString(value: Any) = - value match { - case s: String => s.safeTrim - case a => a - } - - private val operationsMapping = { - import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation._ - - Map[String, SearchFilterBinaryOperation]( - "eq" -> Eq, - "noteq" -> NotEq, - "like" -> Like, - "gt" -> Gt, - "gteq" -> GtEq, - "lt" -> Lt, - "lteq" -> LtEq - ) - } - - private def parseOperation(x: String): Option[SearchFilterBinaryOperation] = operationsMapping.get(x) - - private val whitespaceParser = P(CharPred(_.isSafeWhitespace)) - - val dimensionParser: Parser[SearchFilterExpr.Dimension] = { - val identParser = P( - CharPred(c => c.isLetterOrDigit) - .rep(min = 1)).!.map(s => SearchFilterExpr.Dimension(None, toSnakeCase(s))) - val pathParser = P(identParser.! ~ "." ~ identParser.!) map { - case (left, right) => - SearchFilterExpr.Dimension(Some(toSnakeCase(left)), toSnakeCase(right)) - } - P(pathParser | identParser) - } - - private val commonOperatorParser: Parser[String] = { - P(IgnoreCase("eq") | IgnoreCase("like") | IgnoreCase("noteq")).! - } - - private val numericOperatorParser: Parser[String] = { - P(IgnoreCase("eq") | IgnoreCase("noteq") | ((IgnoreCase("gt") | IgnoreCase("lt")) ~ IgnoreCase("eq").?)).! - } - - private val naryOperatorParser: Parser[String] = P(IgnoreCase("in")).! - - private val isPositiveParser: Parser[Boolean] = P(CharIn("-+").!.?).map { - case Some("-") => false - case _ => true - } - - private val digitsParser: Parser[String] = P(CharIn('0' to '9').rep(min = 1).!) // Exclude Unicode "digits" - - 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" - case (_, intPart, Some(fracPart)) => s"$intPart.${fracPart.tail}" - case (_, intPart, None) => s"$intPart" - } - - private val nAryValueParser: Parser[String] = P(CharPred(_ != ',').rep(min = 1).!) - - private val longParser: Parser[Long] = P(CharIn('0' to '9').rep(min = 1).!.map(_.toLong)) - - 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 | numberParser.!) ~ End) | - (commonOperatorParser.! ~ whitespaceParser ~ (uuidParser | booleanParser | AnyChar.rep(min = 1).!) ~ End)) - ).map { - case BinaryAtomFromTuple(atom) => atom - } - - private val nAryAtomParser: Parser[SearchFilterExpr.Atom.NAry] = P( - dimensionParser ~ whitespaceParser ~ ( - naryOperatorParser ~ whitespaceParser ~ - ((longParser.rep(min = 1, sep = ",") ~ End) | (booleanParser.rep(min = 1, sep = ",") ~ End) | - (nAryValueParser.!.rep(min = 1, sep = ",") ~ End)) - ) - ).map { - case NAryAtomFromTuple(atom) => atom - } - - private val atomParser: Parser[SearchFilterExpr.Atom] = P(binaryAtomParser | nAryAtomParser) - - @deprecated("play-akka transition", "0") - def parse(query: Map[String, Seq[String]]): Try[SearchFilterExpr] = - parse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(query: Seq[(String, String)]): Try[SearchFilterExpr] = Try { - query.toList.collect { case ("filters", value) => value } match { - case Nil => SearchFilterExpr.Empty - - case head :: Nil => - atomParser.parse(head) match { - case Parsed.Success(x, _) => x - case e: Parsed.Failure[_, _] => throw new ParseQueryArgException("filters" -> formatFailure(1, e)) - } - - case xs => - val parsed = xs.map(x => atomParser.parse(x)) - val failures: Seq[String] = parsed.zipWithIndex.collect { - case (e: Parsed.Failure[_, _], index) => formatFailure(index, e) - } - - if (failures.isEmpty) { - val filters = parsed.collect { - case Parsed.Success(x, _) => x - } - - SearchFilterExpr.Intersection.create(filters: _*) - } else { - throw new ParseQueryArgException("filters" -> failures.mkString("; ")) - } - } - } - - private def formatFailure(sectionIndex: Int, e: Parsed.Failure[_, _]): String = { - s"section $sectionIndex: ${fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index)}" - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala deleted file mode 100644 index a04d278..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala +++ /dev/null @@ -1,64 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.db.{Sorting, SortingOrder} -import fastparse.all._ -import fastparse.core.Parsed -import xyz.driver.pdsuicommon.utils.Utils._ - -import scala.util.Try - -object SortingParser { - - private val sortingOrderParser: Parser[SortingOrder] = P("-".!.?).map { - case Some(_) => SortingOrder.Descending - case None => SortingOrder.Ascending - } - - private def dimensionSortingParser(validDimensions: Seq[String]): Parser[Sorting.Dimension] = { - P(sortingOrderParser ~ StringIn(validDimensions: _*).!).map { - case (sortingOrder, field) => - val prefixedFields = field.split("\\.", 2) - prefixedFields.size match { - case 1 => Sorting.Dimension(None, toSnakeCase(field), sortingOrder) - case 2 => - Sorting.Dimension(Some(prefixedFields.head).map(toSnakeCase), - toSnakeCase(prefixedFields.last), - sortingOrder) - } - } - } - - private def sequentialSortingParser(validDimensions: Seq[String]): Parser[Sorting.Sequential] = { - P(dimensionSortingParser(validDimensions).rep(min = 1, sep = ",") ~ End).map { dimensions => - Sorting.Sequential(dimensions) - } - } - - @deprecated("play-akka transition", "0") - def parse(validDimensions: Set[String], query: Map[String, Seq[String]]): Try[Sorting] = - parse(validDimensions, query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(validDimensions: Set[String], query: Seq[(String, String)]): Try[Sorting] = Try { - query.toList.collect { case ("sort", value) => value } match { - case Nil => Sorting.Sequential(Seq.empty) - - case rawSorting :: Nil => - val parser = sequentialSortingParser(validDimensions.toSeq) - parser.parse(rawSorting) match { - case Parsed.Success(x, _) => x - case e: Parsed.Failure[_, _] => - throw new ParseQueryArgException("sort" -> formatFailure(e)) - } - - case _ => throw new ParseQueryArgException("sort" -> "multiple sections are not allowed") - } - } - - private def formatFailure(e: Parsed.Failure[_, _]): String = { - fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala b/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala deleted file mode 100644 index 6702de2..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala +++ /dev/null @@ -1,6 +0,0 @@ -package xyz.driver.pdsuicommon.serialization - -trait Marshaller[T, Repr] { - def read(x: Repr): Option[T] - def write(x: T): Repr -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala deleted file mode 100644 index 63514ec..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import slick.dbio.DBIO - -import scalaz.OptionT - -trait SlickDataSource[T] { - - val isDictionary: Boolean = false - - /** - * @return New entity - */ - def create(x: T): DBIO[T] - - /** - * @return Updated entity - */ - def update(x: T): OptionT[DBIO, T] - - def delete(x: T): OptionT[DBIO, Unit] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala deleted file mode 100644 index 57cc3d4..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala +++ /dev/null @@ -1,70 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import slick.dbio.DBIO -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.synchronization.utils.{FakeIdGen, FakeIdMap} - -import scala.concurrent.ExecutionContext -import scalaz.Monad - -trait SlickDbAction[+T] { - def entity: T -} - -object SlickDbAction { - - final case class Create[T](entity: T) extends SlickDbAction[T] - final case class Update[T](entity: T) extends SlickDbAction[T] - final case class Delete[T](entity: T) extends SlickDbAction[T] - - // Use it only inside of a transaction! - def unsafeRun[T](actions: List[SlickDbAction[T]], dataSource: SlickDataSource[T])( - implicit core: FakeIdGen[T], - executionContext: ExecutionContext, - dbioMonad: Monad[DBIO]): DBIO[FakeIdMap[T]] = { - unsafeRun(DBIO.successful(FakeIdMap.empty))(actions, dataSource) - } - - // Use it only inside of a transaction! - def unsafeRun[T](initial: DBIO[FakeIdMap[T]])(actions: List[SlickDbAction[T]], dataSource: SlickDataSource[T])( - implicit core: FakeIdGen[T], - executionContext: ExecutionContext, - dbioMonad: Monad[DBIO]): DBIO[FakeIdMap[T]] = { - // TODO Squash Updates and Delete to one operation, when bugs in repositories will be fixed - actions.foldLeft(initial) { - case (previousActions, Create(x)) => - for { - r <- previousActions - newArm <- dataSource.create(x) - } yield { - r + (core(newArm) -> newArm) - } - - case (previousActions, Update(x)) => - for { - r <- previousActions - updatedArm <- dataSource.update(x).getOrElse(x) - } yield { - r - core(updatedArm) + (core(updatedArm) -> updatedArm) - } - - case (previousActions, Delete(_)) if dataSource.isDictionary => - previousActions // We don't delete entities from dictionaries - - case (previousActions, Delete(x)) => - for { - r <- previousActions - _ <- dataSource.delete(x).run - } yield { - r - core(x) - } - } - } - - implicit def toPhiString[T](input: SlickDbAction[T])(implicit inner: T => PhiString): PhiString = input match { - case Create(x) => phi"Create($x)" - case Update(x) => phi"Update($x)" - case Delete(x) => phi"Delete($x)" - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala deleted file mode 100644 index c226659..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala +++ /dev/null @@ -1,52 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import xyz.driver.pdsuicommon.synchronization.domain.FakeId -import xyz.driver.pdsuicommon.synchronization.utils.{FakeIdGen, Refiner} - -import scala.annotation.tailrec -import scala.collection.breakOut -import scala.collection.immutable.SortedSet - -object SlickDbDiff { - - /** - * Calculates DB-actions to synchronize origEntities with draftEntities. - */ - def calc[DraftT, OrigT](origEntities: Iterable[OrigT], draftEntities: Iterable[DraftT])( - implicit draftFakeIdGen: FakeIdGen[DraftT], - origFakeIdGen: FakeIdGen[OrigT], - refiner: Refiner[DraftT, OrigT]): List[SlickDbAction[OrigT]] = { - val origMap: Map[FakeId, OrigT] = origEntities.map(x => origFakeIdGen(x) -> x)(breakOut) - val uniqueDraftEntities = SortedSet.newBuilder[DraftT](Ordering.by[DraftT, FakeId](draftFakeIdGen)) - uniqueDraftEntities ++= draftEntities - - loop(origMap, uniqueDraftEntities.result(), List.empty) - } - - @tailrec private def loop[DraftT, OrigT](origEntitiesMap: Map[FakeId, OrigT], - draftEntities: Iterable[DraftT], - actions: List[SlickDbAction[OrigT]])( - implicit draftFakeIdGen: FakeIdGen[DraftT], - refiner: Refiner[DraftT, OrigT]): List[SlickDbAction[OrigT]] = { - draftEntities.headOption match { - case None => - // The rest original entities are not a part of draft, so we will delete them - val toDelete: List[SlickDbAction[OrigT]] = origEntitiesMap.values.map(x => SlickDbAction.Delete(x))(breakOut) - actions ++ toDelete - - case Some(currRaw) => - val rawCore = draftFakeIdGen.getFor(currRaw) - val action: Option[SlickDbAction[OrigT]] = origEntitiesMap.get(rawCore) match { - // It is a new entity, because it doesn't exist among originals - case None => Some(SlickDbAction.Create(refiner.refine(currRaw))) - case Some(orig) => - val draft = refiner.refresh(orig, currRaw) - if (draft == orig) None - else Some(SlickDbAction.Update(draft)) - } - - loop(origEntitiesMap - rawCore, draftEntities.tail, action.map(_ :: actions).getOrElse(actions)) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala deleted file mode 100644 index 38e442b..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.domain - -/* - It is like an Id for entities those haven't an Id, but should be unique. - For example, - RawArm has the name, the kind and the intervention fields. - It has not an Id, but should be identified by the name field. - So, the name field is a fake id for RawArm. - */ -final case class FakeId(value: String) - -object FakeId { - implicit val ordering: Ordering[FakeId] = Ordering.by(_.value) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala deleted file mode 100644 index 196aab1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.utils - -import xyz.driver.pdsuicommon.synchronization.domain.FakeId - -/** - * Used to generate a fake id from an entity. - * A fake id is used in comparison between entities with different types, - * for example, RawTrial and Trial. - * - * @see FakeId - */ -trait FakeIdGen[-T] extends (T => FakeId) { - - def getFor(x: T): FakeId - - override def apply(x: T): FakeId = getFor(x) - -} - -object FakeIdGen { - - def create[T](f: T => FakeId) = new FakeIdGen[T] { - override def getFor(x: T): FakeId = f(x) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala deleted file mode 100644 index 768b889..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala +++ /dev/null @@ -1,12 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.utils - -/** - * Allows to extract a data from the From entity to convert/update in to the To entity. - */ -trait Refiner[-From, To] { - - def refine(raw: From): To - - def refresh(orig: To, update: From): To - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala deleted file mode 100644 index 1b30158..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala +++ /dev/null @@ -1,64 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization - -import java.net.URL -import java.nio.ByteBuffer -import java.util.UUID - -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.http.HttpFetcher -import xyz.driver.pdsuicommon.json.JsonSerializer -import xyz.driver.pdsuicommon.synchronization.domain.FakeId - -import scala.collection.breakOut -import scala.concurrent.{ExecutionContext, Future} -import scala.io.Codec - -package object utils { - - type FakeIdMap[T] = Map[FakeId, T] - - object FakeIdMap { - - def empty[T]: FakeIdMap[T] = Map.empty - - def create[T](xs: Seq[T])(implicit fakeIdExtractor: FakeIdGen[T]): FakeIdMap[T] = { - xs.map({ x => - fakeIdExtractor.getFor(x) -> x - })(breakOut) - } - - } - - /** - * Requests domain objects from the repository using - * ids of fetched dictionary entities - * - * @param getList repository access function - * @param xs sequence of entity objects - * @param id function that extracts id from the entity - * @tparam Id Type of Id (for example [[LongId]], [[UuidId]]) - * @tparam K Type parameter for Id - * @tparam D Domain object type name - * @tparam E Dictionary entity object type name - */ - def domainFromEntities[K, D, E, Id[_]](getList: Set[Id[K]] => Seq[D], xs: Seq[E])(id: E => Id[K]): Seq[D] = { - getList(xs.map(x => id(x)).toSet) - } - - /** Version of [[domainFromEntities]] for LongId */ - def domainFromEntitiesLong[K, D, E](getList: Set[LongId[K]] => Seq[D], xs: Seq[E])(id: E => Long): Seq[D] = { - domainFromEntities(getList, xs)(e => LongId(id(e))) - } - - /** Version of [[domainFromEntities]] for UuidId */ - def domainFromEntitiesUUID[K, D, E](getList: Set[UuidId[K]] => Seq[D], xs: Seq[E])(id: E => UUID): Seq[D] = { - domainFromEntities(getList, xs)(e => UuidId(id(e))) - } - - def fetch[T](httpFetcher: HttpFetcher, url: URL)(implicit m: Manifest[T], ec: ExecutionContext): Future[T] = { - httpFetcher(url).map { rawContent => - val content = Codec.UTF8.decoder.decode(ByteBuffer.wrap(rawContent)).toString - JsonSerializer.deserialize[T](content) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala deleted file mode 100644 index cee9c73..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala +++ /dev/null @@ -1,31 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -final class CharOps(val self: Char) extends AnyVal { - - import CharOps._ - - def isSafeWhitespace: Boolean = Whitespace.matches(self) - - def isSafeControl: Boolean = JavaIsoControl.matches(self) -} - -// From Guava -private object CharOps { - - object Whitespace { - private val Table: String = - "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000" + - "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + - "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" + - "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000" - - private val Multiplier: Int = 1682554634 - private val Shift: Int = Integer.numberOfLeadingZeros(Table.length - 1) - - def matches(c: Char): Boolean = Table.charAt((Multiplier * c) >>> Shift) == c - } - - object JavaIsoControl { - def matches(c: Char): Boolean = c <= '\u001f' || (c >= '\u007f' && c <= '\u009f') - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala deleted file mode 100644 index 27560d5..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala +++ /dev/null @@ -1,218 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.time.{LocalDate, LocalDateTime} - -import io.swagger.models.properties.Property -import spray.json.JsValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.formats.json.listresponse._ -import xyz.driver.core.swagger.CustomSwaggerJsonConverter._ -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels -import xyz.driver.pdsuidomain.entities.export.trial.ExportTrialWithLabels -import xyz.driver.pdsuidomain.fakes.entities.common -import xyz.driver.pdsuidomain.formats.json.bridgeuploadqueue._ -import xyz.driver.pdsuidomain.formats.json.record._ -import xyz.driver.pdsuidomain.formats.json.document._ -import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion -import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData - -import scala.collection.immutable - -object CustomSwaggerJsonFormats { - - trait MedicalRecordListResponse - trait MedicalRecordIssueListResponse - trait MedicalRecordHistoryListResponse - trait DocumentListResponse - trait DocumentIssueListResponse - trait DocumentHistoryListResponse - trait RichExtractedDataListResponse - trait DocumentTypeListResponse - trait ProviderTypeListResponse - - trait TrialListResponse - trait TrialIssueListResponse - trait TrialHistoryListResponse - trait ArmListResponse - trait InterventionWithArmsListResponse - trait EligibilityArmWithDiseasesListResponse - trait SlotArmListResponse - trait RichCriterionListResponse - trait InterventionTypeListResponse - trait StudyDesignListResponse - trait HypothesisListResponse - - trait PatientListResponse - trait PatientIssueListResponse - trait PatientHistoryListResponse - trait PatientLabelListResponse - trait RichPatientLabelListResponse - trait RichPatientCriterionListResponse - trait RichPatientEligibleTrialListResponse - trait PatientHypothesisListResponse - trait PatientLabelEvidenceViewListResponse - - trait QueueUploadItemListResponse - - val customCommonProperties = immutable.Map[Class[_], Property]( - classOf[LocalDateTime] -> stringProperty(example = Some("2010-12-31'T'18:59:59Z")), - classOf[LocalDate] -> stringProperty(example = Some("2010-12-31")), - classOf[UuidId[_]] -> stringProperty(example = Some("370b0450-35cb-4aab-ba74-0145be75add5")), - classOf[StringId[_]] -> stringProperty(), - classOf[LongId[_]] -> stringProperty(), - classOf[CancerType] -> stringProperty() - ) - - val customCommonObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[BridgeUploadQueue.Item] -> queueUploadItemFormat.write(common.nextBridgeUploadQueueItem()), - classOf[ProviderType] -> providerTypeFormat.write(common.nextProviderType()), - classOf[DocumentType] -> documentTypeFormat.write(common.nextDocumentType()), - classOf[QueueUploadItemListResponse] -> listResponseWriter[BridgeUploadQueue.Item] - .write(common.nextBridgeUploadQueueItemListResponse()), - classOf[DocumentTypeListResponse] -> listResponseWriter[DocumentType].write(common.nextDocumentTypeListResponse()), - classOf[ProviderTypeListResponse] -> listResponseWriter[ProviderType].write(common.nextProviderTypeListResponse()) - ) - - object trialcuration { - import xyz.driver.pdsuidomain.fakes.entities.trialcuration._ - import xyz.driver.pdsuidomain.fakes.entities.export - import xyz.driver.pdsuidomain.formats.json.export._ - import xyz.driver.pdsuidomain.formats.json.arm._ - import xyz.driver.pdsuidomain.formats.json.slotarm._ - import xyz.driver.pdsuidomain.formats.json.eligibilityarm._ - import xyz.driver.pdsuidomain.formats.json.criterion._ - import xyz.driver.pdsuidomain.formats.json.intervention._ - import xyz.driver.pdsuidomain.formats.json.hypothesis._ - import xyz.driver.pdsuidomain.formats.json.studydesign._ - import xyz.driver.pdsuidomain.formats.json.trial._ - import xyz.driver.pdsuidomain.formats.json.trialhistory._ - import xyz.driver.pdsuidomain.formats.json.trialissue._ - - val customTrialCurationProperties = immutable.Map[Class[_], Property]( - classOf[Trial.Status] -> stringProperty(), - classOf[TrialHistory.Action] -> stringProperty(), - classOf[TrialHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customTrialCurationObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Trial] -> trialFormat.write(nextTrial()), - classOf[Arm] -> armFormat.write(nextArm()), - classOf[TrialHistory] -> trialHistoryFormat.write(nextTrialHistory()), - classOf[TrialIssue] -> trialIssueWriter.write(nextTrialIssue()), - classOf[RichCriterion] -> richCriterionFormat.write(nextRichCriterion()), - classOf[InterventionWithArms] -> interventionFormat.write(nextInterventionWithArms()), - classOf[InterventionType] -> interventionTypeFormat.write(nextInterventionType()), - classOf[Hypothesis] -> hypothesisFormat.write(nextHypothesis()), - classOf[StudyDesign] -> studyDesignFormat.write(nextStudyDesign()), - classOf[ExportTrialWithLabels] -> trialWithLabelsFormat.write(export.nextExportTrialWithLabels()), - classOf[EligibilityArmWithDiseases] -> eligibilityArmWithDiseasesWriter.write(nextEligibilityArmWithDiseases()), - classOf[SlotArm] -> slotArmFormat.write(nextSlotArm()), - classOf[TrialListResponse] -> listResponseWriter[Trial].write(nextTrialListResponse()), - classOf[TrialIssueListResponse] -> listResponseWriter[TrialIssue].write(nextTrialIssueListResponse()), - classOf[TrialHistoryListResponse] -> listResponseWriter[TrialHistory].write(nextTrialHistoryListResponse()), - classOf[ArmListResponse] -> listResponseWriter[Arm].write(nextArmListResponse()), - classOf[InterventionWithArmsListResponse] -> listResponseWriter[InterventionWithArms].write( - nextInterventionWithArmsListResponse()), - classOf[EligibilityArmWithDiseasesListResponse] -> listResponseWriter[EligibilityArmWithDiseases].write( - nextEligibilityArmWithDiseasesListResponse()), - classOf[SlotArmListResponse] -> listResponseWriter[SlotArm].write(nextSlotArmListResponse()), - classOf[RichCriterionListResponse] -> listResponseWriter[RichCriterion].write(nextRichCriterionListResponse()), - classOf[InterventionTypeListResponse] -> listResponseWriter[InterventionType].write( - nextInterventionTypeListResponse()), - classOf[StudyDesignListResponse] -> listResponseWriter[StudyDesign].write(nextStudyDesignListResponse()), - classOf[HypothesisListResponse] -> listResponseWriter[Hypothesis].write(nextHypothesesListResponse()) - ) - } - - object recordprocessing { - import xyz.driver.pdsuidomain.fakes.entities.recordprocessing._ - import xyz.driver.pdsuidomain.fakes.entities.export - import xyz.driver.pdsuidomain.formats.json.export._ - import xyz.driver.pdsuidomain.formats.json.documentissue._ - import xyz.driver.pdsuidomain.formats.json.documenthistory._ - import xyz.driver.pdsuidomain.formats.json.recordissue._ - import xyz.driver.pdsuidomain.formats.json.recordhistory._ - import xyz.driver.pdsuidomain.formats.json.extracteddata._ - - val customRecordProcessingProperties = immutable.Map[Class[_], Property]( - classOf[MedicalRecord.Status] -> stringProperty(), - classOf[MedicalRecordHistory.Action] -> stringProperty(), - classOf[MedicalRecordHistory.State] -> stringProperty(), - classOf[Document.Status] -> stringProperty(), - classOf[Document.RequiredType] -> stringProperty(), - classOf[DocumentHistory.Action] -> stringProperty(), - classOf[DocumentHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customRecordProcessingObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Document] -> documentFormat.write(nextDocument()), - classOf[DocumentIssue] -> documentIssueFormat.write(nextDocumentIssue()), - classOf[DocumentHistory] -> documentHistoryFormat.write(nextDocumentHistory()), - classOf[MedicalRecord] -> recordFormat.write(nextMedicalRecord()), - classOf[MedicalRecordIssue] -> recordIssueFormat.write(nextMedicalRecordIssue()), - classOf[MedicalRecordHistory] -> recordHistoryFormat.write(nextMedicalRecordHistory()), - classOf[RichExtractedData] -> extractedDataFormat.write(nextRichExtractedData()), - classOf[ExportPatientWithLabels] -> patientWithLabelsFormat.write(export.nextExportPatientWithLabels()), - classOf[MedicalRecordListResponse] -> listResponseWriter[MedicalRecord].write(nextMedicalRecordListResponse()), - classOf[MedicalRecordIssueListResponse] -> listResponseWriter[MedicalRecordIssue].write( - nextMedicalRecordIssueListResponse()), - classOf[MedicalRecordHistoryListResponse] -> listResponseWriter[MedicalRecordHistory].write( - nextMedicalRecordHistoryListResponse()), - classOf[DocumentListResponse] -> listResponseWriter[Document].write(nextDocumentListResponse()), - classOf[DocumentIssueListResponse] -> listResponseWriter[DocumentIssue].write(nextDocumentIssueListResponse()), - classOf[DocumentHistoryListResponse] -> listResponseWriter[DocumentHistory].write( - nextDocumentHistoryListResponse()), - classOf[RichExtractedDataListResponse] -> listResponseWriter[RichExtractedData].write( - nextRichExtractedDataListResponse()) - ) ++ customCommonObjectsExamples - } - - object treatmentmatching { - import xyz.driver.pdsuidomain.fakes.entities.treatmentmatching._ - import xyz.driver.pdsuidomain.formats.json.patient._ - import xyz.driver.pdsuidomain.formats.json.patientcriterion._ - import xyz.driver.pdsuidomain.formats.json.patientdefiningcriteria._ - import xyz.driver.pdsuidomain.formats.json.patienteligibletrial._ - import xyz.driver.pdsuidomain.formats.json.patientlabel._ - import xyz.driver.pdsuidomain.formats.json.patienthypothesis._ - import xyz.driver.pdsuidomain.formats.json.patienthistory._ - import xyz.driver.pdsuidomain.formats.json.patientissue._ - - val customTreatmentMatchingProperties = immutable.Map[Class[_], Property]( - classOf[Patient.Status] -> stringProperty(), - classOf[PatientHistory.Action] -> stringProperty(), - classOf[PatientHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customTreatmentMatchingObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Patient] -> patientFormat.write(nextPatient()), - classOf[RichPatientLabel] -> richPatientLabelFormat.write(nextRichPatientLabel()), - classOf[PatientLabel] -> patientLabelDefiningCriteriaWriter.write(nextPatientLabel()), - classOf[RichPatientCriterion] -> richPatientCriterionFormat.write(nextRichPatientCriterion()), - classOf[DraftPatientCriterion] -> draftPatientCriterionFormat.write(nextDraftPatientCriterion()), - classOf[PatientLabelEvidenceView] -> patientLabelEvidenceWriter.write(nextPatientLabelEvidenceView()), - classOf[RichPatientEligibleTrial] -> patientEligibleTrialWriter.write(nextRichPatientEligibleTrial()), - classOf[PatientHypothesis] -> patientHypothesisWriter.write(nextPatientHypothesis()), - classOf[PatientHistory] -> patientHistoryFormat.write(nextPatientHistory()), - classOf[PatientIssue] -> patientIssueWriter.write(nextPatientIssue()), - classOf[PatientListResponse] -> listResponseWriter[Patient].write(nextPatientListResponse()), - classOf[PatientLabelListResponse] -> listResponseWriter[PatientLabel].write(nextPatientLabelListResponse()), - classOf[RichPatientLabelListResponse] -> listResponseWriter[RichPatientLabel].write( - nextRichPatientLabelListResponse()), - classOf[RichPatientCriterionListResponse] -> listResponseWriter[RichPatientCriterion].write( - nextRichPatientCriterionListResponse()), - classOf[PatientLabelEvidenceViewListResponse] -> listResponseWriter[PatientLabelEvidenceView].write( - nextPatientLabelEvidenceViewListResponse()), - classOf[RichPatientEligibleTrialListResponse] -> listResponseWriter[RichPatientEligibleTrial].write( - nextRichPatientEligibleTrialListResponse()), - classOf[PatientHypothesisListResponse] -> listResponseWriter[PatientHypothesis].write( - nextPatientHypothesisListResponse()), - classOf[PatientIssueListResponse] -> listResponseWriter[PatientIssue].write(nextPatientIssuesListResponse()), - classOf[PatientHistoryListResponse] -> listResponseWriter[PatientHistory].write(nextPatientHistoryListResponse()) - ) ++ customCommonObjectsExamples - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala deleted file mode 100644 index e8b1f5c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala +++ /dev/null @@ -1,18 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Failure, Try} - -object FutureUtils { - - def executeSynchronously[T](f: ExecutionContext => Future[T]): Try[T] = { - val future = f { - new ExecutionContext { - override def reportFailure(cause: Throwable): Unit = cause.printStackTrace() - - override def execute(runnable: Runnable): Unit = runnable.run() - } - } - future.value.getOrElse(Failure(new IllegalStateException("Can not evaluate the result of future"))) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala deleted file mode 100644 index 0b18093..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala +++ /dev/null @@ -1,25 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import scala.collection.generic.CanBuildFrom - -object Implicits { - - final class ConditionalAppend[U, T[U] <: TraversableOnce[U]](val c: T[U]) extends AnyVal { - def condAppend(cond: => Boolean, value: U)(implicit cbf: CanBuildFrom[T[U], U, T[U]]): T[U] = { - val col = cbf() - if (cond) { - ((col ++= c) += value).result - } else { - c.asInstanceOf[T[U]] - } - } - } - - implicit def traversableConditionalAppend[U, T[U] <: TraversableOnce[U]](c: T[U]): ConditionalAppend[U, T] = - new ConditionalAppend[U, T](c) - - implicit def toMapOps[K, V](x: Map[K, V]): MapOps[K, V] = new MapOps(x) - - implicit def toCharOps(self: Char): CharOps = new CharOps(self) - implicit def toStringOps(self: String): StringOps = new StringOps(self) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala deleted file mode 100644 index ac9a162..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala +++ /dev/null @@ -1,10 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -final class MapOps[K, V](val self: Map[K, V]) extends AnyVal { - - def swap: Map[V, Set[K]] = { - self.toList - .groupBy { case (_, v) => v } - .mapValues(_.map { case (k, _) => k }.toSet) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala deleted file mode 100644 index faf8703..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.util.concurrent.ThreadLocalRandom - -import scala.collection._ - -object RandomUtils { - - private def Random = ThreadLocalRandom.current() - - private val chars: Seq[Char] = ('0' to '9') ++ ('a' to 'z') - - def randomString(len: Int): String = { - (0 until len).map({ _ => - val i = Random.nextInt(0, chars.size) - chars(i) - })(breakOut) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala deleted file mode 100644 index 68070f4..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation.Eq -import xyz.driver.pdsuicommon.db.SearchFilterExpr -import xyz.driver.pdsuicommon.db.SearchFilterExpr.{Atom, Dimension} -import xyz.driver.pdsuicommon.logging._ - -import scala.util.{Failure, Success, Try} - -object ServiceUtils extends PhiLogging { - - def findEqFilter(filter: SearchFilterExpr, fieldName: String): Option[SearchFilterExpr] = { - findEqFilter(filter, Dimension(None, fieldName)) - } - - def findEqFilter(filter: SearchFilterExpr, dimension: Dimension): Option[SearchFilterExpr] = { - filter.find { - case Atom.Binary(`dimension`, Eq, _) => true - case _ => false - } - } - - def convertIdInFilterToLong(value: AnyRef): Option[Long] = { - Try(value.toString.toLong) match { - case Success(id) => - Option(id) - case Failure(e) => - logger.error(phi"Incorrect id format in filter $e") - None - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala deleted file mode 100644 index eaac761..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import xyz.driver.pdsuicommon.utils.Implicits.toCharOps - -final class StringOps(val self: String) extends AnyVal { - - def safeTrim: String = { - def shouldKeep(c: Char): Boolean = !c.isSafeControl && !c.isSafeWhitespace - - if (self.isEmpty) { - "" - } else { - val start = self.indexWhere(shouldKeep) - val end = self.lastIndexWhere(shouldKeep) - - if (start >= 0 && end >= 0) { - self.substring(start, end + 1) - } else { - "" - } - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala deleted file mode 100644 index 63b0572..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala +++ /dev/null @@ -1,43 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.time.LocalDateTime -import java.util.regex.{Matcher, Pattern} - -object Utils { - - implicit val localDateTimeOrdering: Ordering[LocalDateTime] = Ordering.fromLessThan(_ isBefore _) - - /** - * Hack to avoid scala compiler bug with getSimpleName - * @see https://issues.scala-lang.org/browse/SI-2034 - */ - def getClassSimpleName(klass: Class[_]): String = { - try { - klass.getSimpleName - } catch { - case _: InternalError => - val fullName = klass.getName.stripSuffix("$") - val fullClassName = fullName.substring(fullName.lastIndexOf(".") + 1) - fullClassName.substring(fullClassName.lastIndexOf("$") + 1) - } - } - - def toSnakeCase(str: String): String = - str - .replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2") - .replaceAll("([a-z\\d])([A-Z])", "$1_$2") - .toLowerCase - - def toCamelCase(str: String): String = { - val sb = new StringBuffer() - def loop(m: Matcher): Unit = if (m.find()) { - m.appendReplacement(sb, m.group(1).toUpperCase()) - loop(m) - } - val m: Matcher = Pattern.compile("_(.)").matcher(str) - loop(m) - m.appendTail(sb) - sb.toString - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala deleted file mode 100644 index 9f466f8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.validation - -final case class ValidationError(message: String) diff --git a/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala deleted file mode 100644 index a41f87a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala +++ /dev/null @@ -1,39 +0,0 @@ -package xyz.driver.pdsuicommon.validation - -import xyz.driver.pdsuicommon.json.JsonSerializer -import xyz.driver.pdsuicommon.logging._ - -import scala.util.control.NonFatal - -object Validators extends PhiLogging { - - type Validator[Input, Refined] = Input => Either[ValidationError, Refined] - - def generic[T, R](message: String)(f: PartialFunction[T, R]): Validator[T, R] = { value => - if (f.isDefinedAt(value)) Right(f(value)) - else Left(ValidationError(message)) - } - - def nonEmpty[T](field: String): Validator[Option[T], T] = generic(s"$field is empty") { - case Some(x) => x - } - - def nonEmptyString(field: String): Validator[String, String] = generic(s"$field is empty") { - case x if x.nonEmpty => x - } - - def deserializableTo[Refined](field: String)(value: String)( - implicit m: Manifest[Refined]): Either[ValidationError, Refined] = { - try { - Right(JsonSerializer.deserialize[Refined](value)) - } catch { - case NonFatal(e) => - logger.error(phi"Can not deserialize the ${Unsafe(field)}: $e") - Left(ValidationError(s"$field is invalid")) - } - } - - def success[T](result: T): Either[Nothing, T] = Right(result) - - def fail(message: String): Either[ValidationError, Nothing] = Left(ValidationError(message)) -} |