aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala')
-rw-r--r--src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala b/src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala
new file mode 100644
index 0000000..07e32b0
--- /dev/null
+++ b/src/main/scala/xyz/driver/core/rest/directives/PathMatchers.scala
@@ -0,0 +1,73 @@
+package xyz.driver.core
+package rest
+package directives
+
+import java.time.Instant
+import java.util.UUID
+
+import akka.http.scaladsl.model.Uri.Path
+import akka.http.scaladsl.server.PathMatcher.{Matched, Unmatched}
+import akka.http.scaladsl.server.{PathMatcher, PathMatcher1, PathMatchers => AkkaPathMatchers}
+import eu.timepit.refined.collection.NonEmpty
+import eu.timepit.refined.refineV
+import xyz.driver.core.time.Time
+
+import scala.util.control.NonFatal
+
+/** Akka-HTTP path matchers for suctom core types */
+trait PathMatchers {
+
+ private def UuidInPath[T]: PathMatcher1[Id[T]] =
+ AkkaPathMatchers.JavaUUID.map((id: UUID) => Id[T](id.toString.toLowerCase))
+
+ def IdInPath[T]: PathMatcher1[Id[T]] = UuidInPath[T] | new PathMatcher1[Id[T]] {
+ def apply(path: Path) = path match {
+ case Path.Segment(segment, tail) => Matched(tail, Tuple1(Id[T](segment)))
+ case _ => Unmatched
+ }
+ }
+
+ def NameInPath[T]: PathMatcher1[Name[T]] = new PathMatcher1[Name[T]] {
+ def apply(path: Path) = path match {
+ case Path.Segment(segment, tail) => Matched(tail, Tuple1(Name[T](segment)))
+ case _ => Unmatched
+ }
+ }
+
+ private def timestampInPath: PathMatcher1[Long] =
+ PathMatcher("""[+-]?\d*""".r) flatMap { string =>
+ try Some(string.toLong)
+ catch { case _: IllegalArgumentException => None }
+ }
+
+ def InstantInPath: PathMatcher1[Instant] =
+ new PathMatcher1[Instant] {
+ def apply(path: Path): PathMatcher.Matching[Tuple1[Instant]] = path match {
+ case Path.Segment(head, tail) =>
+ try Matched(tail, Tuple1(Instant.parse(head)))
+ catch {
+ case NonFatal(_) => Unmatched
+ }
+ case _ => Unmatched
+ }
+ } | timestampInPath.map(Instant.ofEpochMilli)
+
+ def TimeInPath: PathMatcher1[Time] = InstantInPath.map(instant => Time(instant.toEpochMilli))
+
+ def NonEmptyNameInPath[T]: PathMatcher1[NonEmptyName[T]] = new PathMatcher1[NonEmptyName[T]] {
+ def apply(path: Path) = path match {
+ case Path.Segment(segment, tail) =>
+ refineV[NonEmpty](segment) match {
+ case Left(_) => Unmatched
+ case Right(nonEmptyString) => Matched(tail, Tuple1(NonEmptyName[T](nonEmptyString)))
+ }
+ case _ => Unmatched
+ }
+ }
+
+ def RevisionInPath[T]: PathMatcher1[Revision[T]] =
+ PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string =>
+ Some(Revision[T](string))
+ }
+
+}