diff --git a/bijection-finagle-mysql/src/main/scala/com/twitter/bijection/finagle_mysql/MySqlConversions.scala b/bijection-finagle-mysql/src/main/scala/com/twitter/bijection/finagle_mysql/MySqlConversions.scala new file mode 100644 index 000000000..81c64aeb6 --- /dev/null +++ b/bijection-finagle-mysql/src/main/scala/com/twitter/bijection/finagle_mysql/MySqlConversions.scala @@ -0,0 +1,94 @@ +/* +Copyright 2015 Twitter, Inc. + +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 com.twitter.bijection.finagle_mysql + +import com.twitter.finagle.exp.mysql._ +import com.twitter.bijection._ +import java.sql.Timestamp + +/** + * Bijections and injections for mapping twitter-finagle's MySql datatypes to Scala datatypes + * other types. + * + * @author George Leontiev + */ + +trait MySqlBijections { + implicit val byte: Bijection[ByteValue, Byte] = new AbstractBijection[ByteValue, Byte] { + def apply(v: ByteValue) = v.b + override def invert(b: Byte) = ByteValue(b) + } + + implicit val short: Bijection[ShortValue, Short] = new AbstractBijection[ShortValue, Short] { + def apply(s: ShortValue) = s.s + override def invert(s: Short) = ShortValue(s) + } + + implicit val int: Bijection[IntValue, Int] = new AbstractBijection[IntValue, Int] { + def apply(i: IntValue) = i.i + override def invert(i: Int) = IntValue(i) + } + + implicit val long: Bijection[LongValue, Long] = new AbstractBijection[LongValue, Long] { + def apply(l: LongValue) = l.l + override def invert(l: Long) = LongValue(l) + } + + implicit val float: Bijection[FloatValue, Float] = new AbstractBijection[FloatValue, Float] { + def apply(f: FloatValue) = f.f + override def invert(f: Float) = FloatValue(f) + } + + implicit val double: Bijection[DoubleValue, Double] = new AbstractBijection[DoubleValue, Double] { + def apply(d: DoubleValue) = d.d + override def invert(d: Double) = DoubleValue(d) + } + + implicit val string: Bijection[StringValue, String] = new AbstractBijection[StringValue, String] { + def apply(s: StringValue) = s.s + override def invert(s: String) = StringValue(s) + } + + implicit val boolean: Bijection[ByteValue, Boolean] = new AbstractBijection[ByteValue, Boolean] { + def apply(t: ByteValue) = t.b == 1 + override def invert(b: Boolean) = ByteValue(if (b) 1 else 0) + } +} + +trait MySqlInjections { + implicit val timestamp: Injection[Timestamp, Value] = + new AbstractInjection[Timestamp, Value] { + private val UTC = java.util.TimeZone.getTimeZone("UTC") + private val timestampValue = new TimestampValue(UTC, UTC) + def apply(t: Timestamp) = timestampValue(t) + override def invert(v: Value) = Inversion.attempt(v) { v => timestampValue.unapply(v).get } + } + + implicit def nullValue[A]: Injection[NullValue.type, Option[A]] = + new AbstractInjection[NullValue.type, Option[A]] { + def apply(n: NullValue.type) = None + override def invert(n: Option[A]) = Inversion.attempt(n){ n => n.map(_ => NullValue).get } + } + + implicit def emptyValue[A]: Injection[EmptyValue.type, Option[A]] = + new AbstractInjection[EmptyValue.type, Option[A]] { + def apply(n: EmptyValue.type) = None + override def invert(n: Option[A]) = Inversion.attempt(n){ n => n.map(_ => EmptyValue).get } + } +} + +object MySqlConversions extends MySqlBijections with MySqlInjections diff --git a/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala b/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala new file mode 100644 index 000000000..76631b8e3 --- /dev/null +++ b/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala @@ -0,0 +1,89 @@ +/* +Copyright 2015 Twitter, Inc. + +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 com.twitter.bijection.finagle_mysql + +import com.twitter.bijection.{ BaseProperties, Bijection } +import org.scalacheck.Arbitrary +import org.scalatest.{ PropSpec, MustMatchers } +import org.scalatest.prop.PropertyChecks +import com.twitter.finagle.exp.mysql._ +import java.sql.Timestamp +import java.util.Date + +import org.scalacheck.Prop.forAll +import org.scalacheck.Gen +import org.scalacheck.Arbitrary +import org.scalacheck.Arbitrary.arbitrary + +class MySqlConversionLaws extends PropSpec with PropertyChecks with MustMatchers with BaseProperties { + import MySqlConversions._ + + implicit val byteValueArb = Arbitrary(arbitrary[Byte].map(ByteValue.apply)) + implicit val shortValueArb = Arbitrary(arbitrary[Short].map(ShortValue.apply)) + implicit val intValueArb = Arbitrary(arbitrary[Int].map(IntValue.apply)) + implicit val longValueArb = Arbitrary(arbitrary[Long].map(LongValue.apply)) + implicit val floatValueArb = Arbitrary(arbitrary[Float].map(FloatValue.apply)) + implicit val doubleValueArb = Arbitrary(arbitrary[Double].map(DoubleValue.apply)) + implicit val stringValueArb = Arbitrary(arbitrary[String].map(StringValue.apply)) + implicit val timestampValueArb = Arbitrary(arbitrary[Date].map(d => new Timestamp(d.getTime))) + implicit val nullValueArb = Arbitrary(Gen.const(NullValue)) + implicit val emptyValueArb = Arbitrary(Gen.const(EmptyValue)) + implicit val valueArb: Arbitrary[Value] = Arbitrary(Gen.oneOf(arbitrary[ByteValue], + arbitrary[NullValue.type], + arbitrary[EmptyValue.type], + arbitrary[ShortValue], + arbitrary[IntValue], + arbitrary[LongValue], + arbitrary[FloatValue], + arbitrary[DoubleValue], + arbitrary[StringValue])) + + property("Byte") { + isBijection[ByteValue, Byte] + } + property("Short") { + isBijection[ShortValue, Short] + } + property("Int") { + isBijection[IntValue, Int] + } + property("Long") { + isBijection[LongValue, Long] + } + property("Float") { + isBijection[FloatValue, Float] + } + property("Double") { + isBijection[DoubleValue, Double] + } + property("String") { + isBijection[StringValue, String] + } + property("Boolean") { + isBijection[ByteValue, Boolean] + } + + property("Timestamp") { + isInjection[Timestamp, Value] + } + property("Empty") { + isInjection[EmptyValue.type, Option[Int]] + } + property("Null") { + isInjection[NullValue.type, Option[String]] + } +} diff --git a/project/Build.scala b/project/Build.scala index 2a3231b0d..2b8690185 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -143,6 +143,7 @@ object BijectionBuild extends Build { bijectionScrooge, bijectionJson, bijectionUtil, + bijectionFinagleMySql, bijectionClojure, bijectionNetty, bijectionAvro, @@ -237,6 +238,11 @@ object BijectionBuild extends Build { libraryDependencies += "com.twitter" %% "util-core" % "6.20.0" ).dependsOn(bijectionCore % "test->test;compile->compile") + lazy val bijectionFinagleMySql = module("finagle-mysql").settings( + osgiExportAll("com.twitter.bijection.finagle_mysql"), + libraryDependencies += "com.twitter" %% "finagle-mysql" % "6.24.0" + ).dependsOn(bijectionCore % "test->test;compile->compile") + lazy val bijectionClojure = module("clojure").settings( osgiExportAll("com.twitter.bijection.clojure"), libraryDependencies += "org.clojure" % "clojure" % "1.5.1"