aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/xyz/driver/core/core.scala31
-rw-r--r--src/main/scala/xyz/driver/core/database/database.scala24
-rw-r--r--src/main/scala/xyz/driver/core/json.scala34
-rw-r--r--src/main/scala/xyz/driver/core/rest/auth/CachedTokenAuthorization.scala3
4 files changed, 60 insertions, 32 deletions
diff --git a/src/main/scala/xyz/driver/core/core.scala b/src/main/scala/xyz/driver/core/core.scala
index be19f0f..9e6714d 100644
--- a/src/main/scala/xyz/driver/core/core.scala
+++ b/src/main/scala/xyz/driver/core/core.scala
@@ -54,25 +54,34 @@ package object core {
package core {
- final case class Id[+Tag](value: String) extends AnyVal {
- @inline def length: Int = value.length
- override def toString: String = value
+ sealed trait Id[+Tag] {
+ type Value
+ val value: Value
+ @inline def length: Int = toString.length
+ override def toString: String = value.toString
}
+ final case class StringId[+Tag](value: String) extends Id[Tag] { type Value = String }
+ final case class LongId[+Tag](value: Long) extends Id[Tag] { type Value = Long }
+ final case class UuidId[+Tag](value: java.util.UUID) extends Id[Tag] { type Value = java.util.UUID }
+
@SuppressWarnings(Array("org.wartremover.warts.ImplicitConversion"))
object Id {
- implicit def idEqual[T]: Equal[Id[T]] = Equal.equal[Id[T]](_ == _)
- implicit def idOrdering[T]: Ordering[Id[T]] = Ordering.by[Id[T], String](_.value)
+ def apply[T](value: String): StringId[T] = StringId[T](value)
+
+ implicit def idEqual[T, I[_] <: Id[_]]: Equal[I[T]] = Equal.equalA[I[T]]
+ implicit def idOrdering[T, I[_] <: Id[_]](implicit ord: Ordering[I[T]#Value]): Ordering[I[T]] =
+ Ordering.by[I[T], I[T]#Value](_.value)
- sealed class Mapper[E, R] {
- def apply[T >: E](id: Id[R]): Id[T] = Id[E](id.value)
- def apply[T >: R](id: Id[E])(implicit dummy: DummyImplicit): Id[T] = Id[R](id.value)
+ sealed class Mapper[E, R, I[_] <: Id[_]] {
+ def apply[T >: E](id: I[R]): I[T] = id.asInstanceOf[I[T]]
+ def apply[T >: R](id: I[E])(implicit dummy: DummyImplicit): I[T] = id.asInstanceOf[I[T]]
}
object Mapper {
- def apply[E, R] = new Mapper[E, R]
+ def apply[E, R, I[_] <: Id[_]] = new Mapper[E, R, I]
}
- implicit def convertRE[R, E](id: Id[R])(implicit mapper: Mapper[E, R]): Id[E] = mapper[E](id)
- implicit def convertER[E, R](id: Id[E])(implicit mapper: Mapper[E, R]): Id[R] = mapper[R](id)
+ implicit def convertRE[R, E, I[_] <: Id[_]](id: I[R])(implicit mapper: Mapper[E, R, I]): I[E] = mapper[E](id)
+ implicit def convertER[E, R, I[_] <: Id[_]](id: I[E])(implicit mapper: Mapper[E, R, I]): I[R] = mapper[R](id)
}
final case class Name[+Tag](value: String) extends AnyVal {
diff --git a/src/main/scala/xyz/driver/core/database/database.scala b/src/main/scala/xyz/driver/core/database/database.scala
index ae06517..30adbf6 100644
--- a/src/main/scala/xyz/driver/core/database/database.scala
+++ b/src/main/scala/xyz/driver/core/database/database.scala
@@ -93,30 +93,30 @@ package database {
}
}
- trait IdColumnTypes extends ColumnTypes {
+ trait IdColumnTypes[I[_] <: Id[_]] extends ColumnTypes {
import profile.api._
- implicit def `xyz.driver.core.Id.columnType`[T]: BaseColumnType[Id[T]]
+ implicit def `xyz.driver.core.Id.columnType`[T]: BaseColumnType[I[T]]
}
object IdColumnTypes {
- trait UUID extends IdColumnTypes {
+ trait UUID extends IdColumnTypes[UuidId] {
import profile.api._
override implicit def `xyz.driver.core.Id.columnType`[T] =
MappedColumnType
- .base[Id[T], java.util.UUID](id => java.util.UUID.fromString(id.value), uuid => Id[T](uuid.toString))
+ .base[UuidId[T], java.util.UUID](_.value, UuidId[T])
}
- trait SerialId extends IdColumnTypes {
+ trait SerialId extends IdColumnTypes[LongId] {
import profile.api._
override implicit def `xyz.driver.core.Id.columnType`[T] =
- MappedColumnType.base[Id[T], Long](_.value.toLong, serialId => Id[T](serialId.toString))
+ MappedColumnType.base[LongId[T], Long](_.value, LongId[T])
}
- trait NaturalId extends IdColumnTypes {
+ trait NaturalId extends IdColumnTypes[StringId] {
import profile.api._
override implicit def `xyz.driver.core.Id.columnType`[T] =
- MappedColumnType.base[Id[T], String](_.value, Id[T])
+ MappedColumnType.base[StringId[T], String](_.value, StringId[T])
}
}
@@ -146,11 +146,9 @@ package database {
trait KeyMappers extends ColumnTypes {
import profile.api._
- def uuidKeyMapper[T] =
- MappedColumnType
- .base[Id[T], java.util.UUID](id => java.util.UUID.fromString(id.value), uuid => Id[T](uuid.toString))
- def serialKeyMapper[T] = MappedColumnType.base[Id[T], Long](_.value.toLong, serialId => Id[T](serialId.toString))
- def naturalKeyMapper[T] = MappedColumnType.base[Id[T], String](_.value, Id[T])
+ def uuidKeyMapper[T] = MappedColumnType.base[UuidId[T], java.util.UUID](_.value, UuidId[T])
+ def serialKeyMapper[T] = MappedColumnType.base[LongId[T], Long](_.value, LongId[T])
+ def naturalKeyMapper[T] = MappedColumnType.base[StringId[T], String](_.value, StringId[T])
}
trait DatabaseObject extends ColumnTypes {
diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala
index 02a35fd..c18cadf 100644
--- a/src/main/scala/xyz/driver/core/json.scala
+++ b/src/main/scala/xyz/driver/core/json.scala
@@ -22,18 +22,38 @@ import eu.timepit.refined.collection.NonEmpty
object json {
import DefaultJsonProtocol._
- private def UuidInPath[T]: PathMatcher1[Id[T]] =
- PathMatchers.JavaUUID.map((id: UUID) => Id[T](id.toString.toLowerCase))
+ def UuidInPath[T]: PathMatcher1[UuidId[T]] = PathMatchers.JavaUUID.map(UuidId[T])
+ def LongIdInPath[T]: PathMatcher1[LongId[T]] = PathMatchers.LongNumber.map(LongId[T])
+ def StringIdInPath[T]: PathMatcher1[StringId[T]] = PathMatchers.Segment.map(StringId[T])
- 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 IdInPath[T]: PathMatcher1[Id[T]] = UuidInPath[T] | LongIdInPath[T] | StringIdInPath[T]
+
+ implicit def stringIdFormat[T]: JsonFormat[StringId[T]] = new JsonFormat[StringId[T]] {
+ override def read(json: JsValue): StringId[T] = json match {
+ case JsString(s) => StringId[T](s)
+ case _ => deserializationError(s"Expected string for ID, got $json")
+ }
+ override def write(obj: StringId[T]): JsValue = JsString(obj.value)
+ }
+
+ implicit def uuidIdFormat[T]: JsonFormat[UuidId[T]] = new JsonFormat[UuidId[T]] {
+ override def read(json: JsValue): UuidId[T] = json match {
+ case JsString(s) => UuidId[T](Try(UUID.fromString(s)).getOrElse(deserializationError(s"Invalid UUID format: $s")))
+ case _ => deserializationError(s"Expected UUID string for ID, got $json")
+ }
+ override def write(obj: UuidId[T]): JsValue = JsString(obj.toString)
+ }
+
+ implicit def longIdFormat[T]: JsonFormat[LongId[T]] = new JsonFormat[LongId[T]] {
+ override def read(json: JsValue): LongId[T] = json match {
+ case JsNumber(n) => LongId[T](n.toLong)
+ case _ => deserializationError(s"Expected number for ID, got $json")
}
+ override def write(obj: LongId[T]): JsValue = JsNumber(obj.value)
}
implicit def idFormat[T] = new RootJsonFormat[Id[T]] {
- def write(id: Id[T]) = JsString(id.value)
+ def write(id: Id[T]) = JsString(id.toString)
def read(value: JsValue) = value match {
case JsString(id) if Try(UUID.fromString(id)).isSuccess => Id[T](id.toLowerCase)
diff --git a/src/main/scala/xyz/driver/core/rest/auth/CachedTokenAuthorization.scala b/src/main/scala/xyz/driver/core/rest/auth/CachedTokenAuthorization.scala
index 66de4ef..38e52bc 100644
--- a/src/main/scala/xyz/driver/core/rest/auth/CachedTokenAuthorization.scala
+++ b/src/main/scala/xyz/driver/core/rest/auth/CachedTokenAuthorization.scala
@@ -7,6 +7,7 @@ import java.security.spec.X509EncodedKeySpec
import pdi.jwt.{Jwt, JwtAlgorithm}
import xyz.driver.core.auth.{Permission, User}
import xyz.driver.core.rest.ServiceRequestContext
+import xyz.driver.core.json.idFormat
import scala.concurrent.Future
import scalaz.syntax.std.boolean._
@@ -30,7 +31,7 @@ class CachedTokenAuthorization[U <: User](publicKey: => PublicKey, issuer: Strin
jwtJson = jwt.parseJson.asJsObject
// Ensure jwt is for the currently authenticated user and the correct issuer, otherwise return None
- _ <- jwtJson.fields.get("sub").contains(JsString(user.id.value)).option(())
+ _ <- jwtJson.fields.get("sub").contains(user.id.toJson).option(())
_ <- jwtJson.fields.get("iss").contains(JsString(issuer)).option(())
permissionsMap <- extractPermissionsFromTokenJSON(jwtJson)