From 6f2b9f8aee927e5b909872a7e69e26a54ce4e446 Mon Sep 17 00:00:00 2001 From: Alexis Hernandez Date: Sat, 14 Apr 2018 23:21:08 -0500 Subject: [PATCH] server: Add FieldOrderingParser --- .../xsn/explorer/errors/orderingErrors.scala | 36 +++++++++++ .../explorer/models/base/FieldOrdering.scala | 3 + .../models/base/OrderingCondition.scala | 9 +++ .../explorer/models/base/OrderingQuery.scala | 3 + .../parsers/FieldOrderingParser.scala | 64 +++++++++++++++++++ server/conf/messages | 4 ++ 6 files changed, 119 insertions(+) create mode 100644 server/app/com/xsn/explorer/errors/orderingErrors.scala create mode 100644 server/app/com/xsn/explorer/models/base/FieldOrdering.scala create mode 100644 server/app/com/xsn/explorer/models/base/OrderingCondition.scala create mode 100644 server/app/com/xsn/explorer/models/base/OrderingQuery.scala create mode 100644 server/app/com/xsn/explorer/parsers/FieldOrderingParser.scala diff --git a/server/app/com/xsn/explorer/errors/orderingErrors.scala b/server/app/com/xsn/explorer/errors/orderingErrors.scala new file mode 100644 index 0000000..1ed05fe --- /dev/null +++ b/server/app/com/xsn/explorer/errors/orderingErrors.scala @@ -0,0 +1,36 @@ +package com.xsn.explorer.errors + +import com.alexitc.playsonify.models.{FieldValidationError, InputValidationError, PublicError} +import play.api.i18n.{Lang, MessagesApi} + +sealed trait OrderingError + +case object UnknownOrderingFieldError extends OrderingError with InputValidationError { + + override def toPublicErrorList(messagesApi: MessagesApi)(implicit lang: Lang): List[PublicError] = { + val message = messagesApi("error.ordering.unknownField") + val error = FieldValidationError("orderBy", message) + + List(error) + } +} + +case object InvalidOrderingConditionError extends OrderingError with InputValidationError { + + override def toPublicErrorList(messagesApi: MessagesApi)(implicit lang: Lang): List[PublicError] = { + val message = messagesApi("error.ordering.unknownCondition") + val error = FieldValidationError("orderBy", message) + + List(error) + } +} + +case object InvalidOrderingError extends OrderingError with InputValidationError { + + override def toPublicErrorList(messagesApi: MessagesApi)(implicit lang: Lang): List[PublicError] = { + val message = messagesApi("error.ordering.invalid") + val error = FieldValidationError("orderBy", message) + + List(error) + } +} diff --git a/server/app/com/xsn/explorer/models/base/FieldOrdering.scala b/server/app/com/xsn/explorer/models/base/FieldOrdering.scala new file mode 100644 index 0000000..cd898f2 --- /dev/null +++ b/server/app/com/xsn/explorer/models/base/FieldOrdering.scala @@ -0,0 +1,3 @@ +package com.xsn.explorer.models.base + +case class FieldOrdering[+A](field: A, orderingCondition: OrderingCondition) diff --git a/server/app/com/xsn/explorer/models/base/OrderingCondition.scala b/server/app/com/xsn/explorer/models/base/OrderingCondition.scala new file mode 100644 index 0000000..6342310 --- /dev/null +++ b/server/app/com/xsn/explorer/models/base/OrderingCondition.scala @@ -0,0 +1,9 @@ +package com.xsn.explorer.models.base + +sealed trait OrderingCondition + +object OrderingCondition { + + case object AscendingOrder extends OrderingCondition + case object DescendingOrder extends OrderingCondition +} diff --git a/server/app/com/xsn/explorer/models/base/OrderingQuery.scala b/server/app/com/xsn/explorer/models/base/OrderingQuery.scala new file mode 100644 index 0000000..5dfd18c --- /dev/null +++ b/server/app/com/xsn/explorer/models/base/OrderingQuery.scala @@ -0,0 +1,3 @@ +package com.xsn.explorer.models.base + +case class OrderingQuery(string: String) extends AnyVal diff --git a/server/app/com/xsn/explorer/parsers/FieldOrderingParser.scala b/server/app/com/xsn/explorer/parsers/FieldOrderingParser.scala new file mode 100644 index 0000000..2c7af2a --- /dev/null +++ b/server/app/com/xsn/explorer/parsers/FieldOrderingParser.scala @@ -0,0 +1,64 @@ +package com.xsn.explorer.parsers + +import com.alexitc.playsonify.core.{ApplicationErrors, ApplicationResult} +import com.xsn.explorer.errors.{InvalidOrderingConditionError, InvalidOrderingError, UnknownOrderingFieldError} +import com.xsn.explorer.models.base.{FieldOrdering, OrderingCondition, OrderingQuery} +import org.scalactic._ + +trait FieldOrderingParser[+A] { + + protected def parseField(unsafeField: String): Option[A] + + protected def defaultField: A + + protected def defaultOrderingCondition: OrderingCondition = OrderingCondition.AscendingOrder + + /** + * Accepts values in the format field[:condition], being condition + * an optional argument allowing the these values: + * - asc: for ascending order. + * - desc: for descending order. + * + * The empty string is also accepted returning a default ordering. + */ + def from(orderByQuery: OrderingQuery): ApplicationResult[FieldOrdering[A]] = { + Option(orderByQuery.string) + .filter(_.nonEmpty) + .map { string => from(string.split(":")) } + .getOrElse { + val ordering = FieldOrdering(defaultField, defaultOrderingCondition) + Good(ordering) + } + } + + private def from(parts: Seq[String]): FieldOrdering[A] Or ApplicationErrors = parts match { + case Seq(unsafeField) => + for { + field <- getFieldResult(unsafeField) + } yield FieldOrdering(field, defaultOrderingCondition) + + case Seq(unsafeField, unsafeOrderingCondition) => + Accumulation.withGood( + getFieldResult(unsafeField), + getOrderingConditionResult(unsafeOrderingCondition)) { FieldOrdering.apply } + + case _ => + Bad(InvalidOrderingError).accumulating + } + + private def getFieldResult(unsafeField: String) = { + val maybe = parseField(unsafeField) + Or.from(maybe, One(UnknownOrderingFieldError)) + } + + private def getOrderingConditionResult(unsafeOrderingCondition: String) = { + val maybe = parseOrderingCondition(unsafeOrderingCondition) + Or.from(maybe, One(InvalidOrderingConditionError)) + } + + protected def parseOrderingCondition(unsafeOrderingCondition: String): Option[OrderingCondition] = unsafeOrderingCondition match { + case "asc" => Some(OrderingCondition.AscendingOrder) + case "desc" => Some(OrderingCondition.DescendingOrder) + case _ => None + } +} diff --git a/server/conf/messages b/server/conf/messages index 2d5e29c..b078e70 100644 --- a/server/conf/messages +++ b/server/conf/messages @@ -12,3 +12,7 @@ error.block.notFound=Block not found error.paginatedQuery.offset.invalid=Invalid offset, it should be a number greater or equal than 0 error.paginatedQuery.limit.invalid=Invalid limit, it should be a number between 1 and and {0} + +error.ordering.unknownField=Unknown ordering field +error.ordering.unknownCondition=Unknown ordering condition +error.ordering.invalid=Invalid format