![JAR search and dependency download from the Maven repository](/logo.png)
datomisca.toAndFromDatomic.scala Maven / Gradle / Ivy
/*
* Copyright 2012 Pellucid and Zenexity
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package datomisca
import clojure.lang.IPersistentCollection
import java.util
import scala.annotation.implicitNotFound
/** Injective form of DatomicData to Scala converter :
* - 1 DD => 1 Scala type
* - used when precise type inference by compiler
*/
@implicitNotFound("There is no unique conversion from Datomic data type ${DD} to type ${A}")
sealed trait FromDatomicInj[DD <: AnyRef, A] {
def from(dd: DD): A
}
object FromDatomicInj extends FromDatomicInjImplicits {
def apply[DD <: AnyRef, A](f: DD => A) = new FromDatomicInj[DD, A]{
def from(dd: DD): A = f(dd)
}
}
/** Surjective for DatomicData to Scala converter :
* - n DD => 1 Scala type
*/
@implicitNotFound("There is no conversion from Datomic data type ${DD} to type ${A}. Consider implementing an instance of the FromDatomic type class.")
trait FromDatomic[DD <: AnyRef, A] {
def from(dd: DD): A
}
object FromDatomic extends FromDatomicImplicits {
def apply[DD <: AnyRef, A](f: DD => A) = new FromDatomic[DD, A]{
def from(dd: DD): A = f(dd)
}
}
/** Generic DatomicData to Scala type
* Multi-valued "function" (not real function actually)
* which inverse is surjective ToDatomic or ToDatomicCast
* 1 DatomicData -> n Scala type
*/
@implicitNotFound("There is no cast available from Datomic data to type ${A}")
trait FromDatomicCast[A] {
def from(dd: AnyRef): A
}
object FromDatomicCast extends FromDatomicCastImplicits {
def apply[A](f: AnyRef => A) = new FromDatomicCast[A] {
def from(dd: AnyRef): A = f(dd)
}
}
/** Injective form of Scala to Specific DatomicData converters
* 1 Scala type => 1 DD
*/
@implicitNotFound("There is no unique conversion from type ${A} to Datomic data type ${DD}")
sealed trait ToDatomicInj[DD <: AnyRef, A] {
def to(a: A): DD
}
object ToDatomicInj extends ToDatomicInjImplicits {
def apply[DD <: AnyRef, A](f: A => DD) = new ToDatomicInj[DD, A] {
def to(a: A) = f(a)
}
}
/** Surjective form of Scala to Specific DatomicData converters
* n Scala type => 1 DD
*/
@implicitNotFound("There is no conversion from type ${A} to Datomic data type ${DD}. Consider implementing an instance of the ToDatomic type class.")
trait ToDatomic[DD <: AnyRef, A] {
def to(a: A): DD
}
object ToDatomic extends ToDatomicImplicits{
def apply[DD <: AnyRef, A](f: A => DD) = new ToDatomic[DD, A] {
def to(a: A) = f(a)
}
}
/** Scala type to Generic DatomicData (surjective)
* n Scala type -> DatomicData
*/
@implicitNotFound("There is no cast available from type ${A} to Datomic data")
trait ToDatomicCast[A] {
def to(a: A): AnyRef
}
object ToDatomicCast extends ToDatomicCastImplicits {
def apply[A](f: A => AnyRef): ToDatomicCast[A] = new ToDatomicCast[A] {
def to(a: A): AnyRef = f(a)
}
}
import java.{lang => jl}
import java.math.{BigInteger => JBigInt, BigDecimal => JBigDecimal}
import java.{util => ju}
import java.util.{Date, UUID}
import java.net.URI
/**
* Think of FromDatomicInj[DD, T] as a type-level function: DD => T
* The implicits here construct a multi-parameter type class,
* and there is a functional dependency from DD to T: DD uniquely
* determines T. In fact, this is an injective function, as there
* is at most one FromDatomicInj for each DatomicData subtype, and each
* map to distinct Scala/Java types. As a consequence, its inverse
* is a partial function.
*/
private[datomisca] trait FromDatomicInjImplicits {
implicit val DString2String: FromDatomicInj[String, String] = FromDatomicInj(identity)
implicit val DBoolean2Boolean: FromDatomicInj[jl.Boolean, Boolean] = FromDatomicInj(b => b)
implicit val DLong2Long: FromDatomicInj[jl.Long, Long] = FromDatomicInj(l => l)
implicit val DDouble2Double: FromDatomicInj[jl.Double, Double] = FromDatomicInj(d => d)
implicit val DFloat2Float: FromDatomicInj[jl.Float, Float] = FromDatomicInj(f => f)
implicit val DBigInt2BigInt: FromDatomicInj[JBigInt, BigInt] = FromDatomicInj(i => new BigInt(i))
implicit val DBigDec2BigDec: FromDatomicInj[JBigDecimal, BigDecimal] = FromDatomicInj(d => new BigDecimal(d))
implicit val DInstant2Date: FromDatomicInj[Date, Date] = FromDatomicInj(identity)
implicit val DUuid2UUID: FromDatomicInj[UUID, UUID] = FromDatomicInj(identity)
implicit val DUri2URI: FromDatomicInj[URI, URI] = FromDatomicInj(identity)
implicit val DBytes2Bytes: FromDatomicInj[Array[Byte], Array[Byte]] = FromDatomicInj(identity)
implicit val DKeyword2Keyword: FromDatomicInj[Keyword, Keyword] = FromDatomicInj(identity)
implicit val entity2Entity: FromDatomicInj[datomic.Entity, Entity] = FromDatomicInj(e => new Entity(e))
}
/**
* A multi-valued function, or relation, from DD => T,
* So the type T is no longer uniquely determined by DD.
* For example, DLong maps to DLong, Long, Int, Short,
* Char, and Byte.
*/
trait FromDatomicImplicits {
implicit def FromDatomicInj2FromDatomic[DD <: AnyRef, T]
(implicit fd: FromDatomicInj[DD, T]): FromDatomic[DD, T] =
FromDatomic[DD, T](fd.from(_))
implicit val DLong2Int: FromDatomic[jl.Long, Int] = FromDatomic(_.toInt)
implicit val DLong2Char: FromDatomic[jl.Long, Short] = FromDatomic(_.toShort)
implicit val DLong2Short: FromDatomic[jl.Long, Char] = FromDatomic(_.toChar)
implicit val DLong2Byte: FromDatomic[jl.Long, Byte] = FromDatomic(_.toByte)
implicit val DBigInt2JBigInt: FromDatomic[JBigInt, JBigInt] = FromDatomic(identity)
implicit val DBigDec2JBigDec: FromDatomic[JBigDecimal, JBigDecimal] = FromDatomic(identity)
// implicit def DD2DD[DD <: DatomicData] = FromDatomic[DD, DD]( dd => dd )
implicit def JavaSetToScalaSet[T](implicit conv: FromDatomicCast[T]): FromDatomic[ju.Set[AnyRef], Set[T]] = new FromDatomic[ju.Set[AnyRef], Set[T]] {
override def from(l: ju.Set[AnyRef]) = {
val builder = Set.newBuilder[T]
val iter = l.iterator
while (iter.hasNext) {
builder += conv.from(iter.next())
}
builder.result
}
}
implicit def JavaListToScalaSeq[T](implicit conv: FromDatomicCast[T]): FromDatomic[ju.List[AnyRef], Seq[T]] = new FromDatomic[ju.List[AnyRef], Seq[T]] {
override def from(l: ju.List[AnyRef]) = {
val builder = Seq.newBuilder[T]
val iter = l.iterator
while (iter.hasNext) {
builder += conv.from(iter.next())
}
builder.result
}
}
}
/**
* FromDatomicCast fixes the source type
* of FromDatomic as DatomicData
* Trivially, is a multi-valued function
* from DatomicData => T
*/
trait FromDatomicCastImplicits {
implicit def FromDatomic2FromDatomicCast[DD <: AnyRef, A](implicit fdat: FromDatomic[DD, A]) =
FromDatomicCast{ (dd: Any) => fdat.from(dd.asInstanceOf[DD]) }
}
/**
* Think of ToDatomicInj[DD, T] as a type-level function: T => DD
* The implicits here construct a multi-parameter type class,
* and there is a functional dependency from T to DD: T uniquely
* determines DD. In fact, this is an injective function, as there
* is at most one ToDatomicInj for any Scala type, and each
* map to distinct DatomicData subtypes. As a consequence, its inverse
* is a partial function.
*/
trait ToDatomicInjImplicits {
implicit val String2DString = ToDatomicInj[String, String](identity)
implicit val Boolean2DBoolean = ToDatomicInj[jl.Boolean, Boolean](identity)
implicit val Long2DLong = ToDatomicInj[jl.Long, Long](identity)
implicit val Double2DDouble = ToDatomicInj[jl.Double, Double](identity)
implicit val Float2DFloat = ToDatomicInj[jl.Float, Float](identity)
implicit val BigInt2DBigInt = ToDatomicInj[JBigInt, BigInt]((i: BigInt) => i.bigInteger)
implicit val BigDec2DBigDec = ToDatomicInj[JBigDecimal, BigDecimal]((i: BigDecimal) => i.bigDecimal)
implicit val Date2DDate = ToDatomicInj[Date, Date](identity)
implicit val UUID2DUuid = ToDatomicInj[UUID, UUID](identity)
implicit val URI2DUri = ToDatomicInj[URI, URI](identity)
implicit val Bytes2DBytes = ToDatomicInj[Array[Byte], Array[Byte]](identity)
implicit val Keyword2DKeyword = ToDatomicInj[Keyword, Keyword](identity)
}
/**
* ToDatomic extends ToDatomicInj by widening the domain
* and also destroying the injectivity property
* (both Long and Int map to DLong)
* But it is still a function (unlike FromDatomic)
*/
trait ToDatomicImplicits {
implicit def ToDatomicInj2ToDatomic[DD <: AnyRef, T]
(implicit tdat: ToDatomicInj[DD, T]): ToDatomic[DD, T] =
ToDatomic[DD, T](tdat.to(_))
implicit val Int2DLong = ToDatomic[jl.Long, Int](_.toLong)
implicit val Short2DLong = ToDatomic[jl.Long, Short](_.toLong)
implicit val Char2DLong = ToDatomic[jl.Long, Char](_.toLong)
implicit val Byte2DLong = ToDatomic[jl.Long, Byte](_.toLong)
implicit val JBigInt2DBigInt = ToDatomic[JBigInt, JBigInt](identity)
implicit val JBigDec2DBigDec = ToDatomic[JBigDecimal, JBigDecimal](identity)
implicit def DColl2SetWrites[C, A](implicit ev: C <:< Iterable[A], conv: ToDatomicCast[A]): ToDatomic[util.List[AnyRef], C] = new ToDatomic[ju.List[AnyRef], C] {
override def to(c: C): util.List[AnyRef] = {
val builder = Seq.newBuilder[AnyRef]
for (e <- c) builder += conv.to(e)
datomic.Util.list(builder.result: _*).asInstanceOf[ju.List[AnyRef]]
}
}
implicit val dbConv: ToDatomic[datomic.Database, Database] = ToDatomic[datomic.Database, Database](_.underlying)
implicit val datomConv: ToDatomic[datomic.Datom, Datom] = ToDatomic[datomic.Datom, Datom](_.underlying)
implicit val rulesConv: ToDatomic[IPersistentCollection, QueryRules] = ToDatomic[clojure.lang.IPersistentCollection, QueryRules](_.edn)
implicit val logConv: ToDatomic[datomic.Log, Log] = ToDatomic[datomic.Log, Log](_.log)
}
/**
* ToDatomicCast fixes the return type of ToDatomic as DatomicData
*/
trait ToDatomicCastImplicits {
implicit def DDWriter2ToDatomicCast[DD <: AnyRef, A](implicit tdat: ToDatomic[DD, A]): ToDatomicCast[A] =
ToDatomicCast[A] { (a: A) => tdat.to(a): AnyRef }
implicit def DIdCast[I <: DId]: ToDatomicCast[I] = ToDatomicCast[I] { (i: I) => i.toDatomicId }
implicit def KeywordIdentified2DRef[I <: KeywordIdentified]: ToDatomicCast[I] = ToDatomicCast[I] { (i: I) => i.ident }
implicit def TempIdentified2DRef [I <: TempIdentified]: ToDatomicCast[I] = ToDatomicCast[I] { (i: I) => i.id.toDatomicId }
implicit def FinalIdentified2DRef [I <: FinalIdentified]: ToDatomicCast[I] = ToDatomicCast[I] { (i: I) => i.id }
implicit val JavaListCast: ToDatomicCast[util.List[AnyRef]] = ToDatomicCast[ju.List[AnyRef]](identity)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy