Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added bijection-hbase module #135

Merged
merged 2 commits into from
Jul 12, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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.hbase

import com.twitter.bijection._
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import scala.annotation.implicitNotFound

/**
* Provides various HBase specific Bijections by wrapping org.apache.hadoop.hbase.util.Bytes
* @author Muhammad Ashraf
* @since 7/9/13
*/
object HBaseBijections {
/** Byte Representation of a String value */
type StringBytes = Array[Byte] @@ Rep[String]

/** Byte Representation of a Long value */
type LongBytes = Array[Byte] @@ Rep[Long]

/** Byte Representation of a Boolean value */
type BooleanBytes = Array[Byte] @@ Rep[Boolean]

/** Byte Representation of a Int value */
type IntBytes = Array[Byte] @@ Rep[Int]

/** Byte Representation of a Double value */
type DoubleBytes = Array[Byte] @@ Rep[Double]

/** Byte Representation of a Float value */
type FloatBytes = Array[Byte] @@ Rep[Float]

/** Byte Representation of a Short value */
type ShortBytes = Array[Byte] @@ Rep[Short]

/** Byte Representation of a BigDecimal value */
type BigDecimalBytes = Array[Byte] @@ Rep[BigDecimal]


implicit lazy val string2Bytes: Bijection[String, StringBytes] =
new AbstractBijection[String, StringBytes] {
def apply(str: String) = Tag[Array[Byte], Rep[String]](Bytes.toBytes(str))

override def invert(bytes: StringBytes) = Bytes.toString(bytes)
}

implicit lazy val long2Bytes: Bijection[Long, LongBytes] =
new AbstractBijection[Long, LongBytes] {
def apply(input: Long) = Tag[Array[Byte], Rep[Long]](Bytes.toBytes(input))

override def invert(bytes: LongBytes) = Bytes.toLong(bytes)
}

implicit lazy val boolean2Bytes: Bijection[Boolean, BooleanBytes] =
new AbstractBijection[Boolean, BooleanBytes] {
def apply(input: Boolean) = Tag[Array[Byte], Rep[Boolean]](Bytes.toBytes(input))

override def invert(bytes: BooleanBytes) = Bytes.toBoolean(bytes)
}

implicit lazy val int2Bytes: Bijection[Int, IntBytes] =
new AbstractBijection[Int, IntBytes] {
def apply(input: Int) = Tag[Array[Byte], Rep[Int]](Bytes.toBytes(input))

override def invert(bytes: IntBytes) = Bytes.toInt(bytes)
}

implicit lazy val float2Bytes: Bijection[Float, FloatBytes] =
new AbstractBijection[Float, FloatBytes] {
def apply(input: Float) = Tag[Array[Byte], Rep[Float]](Bytes.toBytes(input))

override def invert(bytes: FloatBytes) = Bytes.toFloat(bytes)
}

implicit lazy val short2Bytes: Bijection[Short, ShortBytes] =
new AbstractBijection[Short, ShortBytes] {
def apply(input: Short) = Tag[Array[Byte], Rep[Short]](Bytes.toBytes(input))

override def invert(bytes: ShortBytes) = Bytes.toShort(bytes)
}

implicit lazy val double2Bytes: Bijection[Double, DoubleBytes] =
new AbstractBijection[Double, DoubleBytes] {
def apply(input: Double) = Tag[Array[Byte], Rep[Double]](Bytes.toBytes(input))

override def invert(bytes: DoubleBytes) = Bytes.toDouble(bytes)
}

implicit lazy val bigdecimal2Bytes: Bijection[BigDecimal, BigDecimalBytes] =
new AbstractBijection[BigDecimal, BigDecimalBytes] {
def apply(input: BigDecimal) = Tag[Array[Byte], Rep[BigDecimal]](Bytes.toBytes(input.underlying()))

override def invert(bytes: BigDecimalBytes) = Bytes.toBigDecimal(bytes)
}

implicit lazy val string2BytesWritable = ImmutableBytesWritableBijection[String]
implicit lazy val int2BytesWritable = ImmutableBytesWritableBijection[Int]
implicit lazy val long2BytesWritable = ImmutableBytesWritableBijection[Long]
implicit lazy val double2BytesWritable = ImmutableBytesWritableBijection[Double]
implicit lazy val float2BytesWritable = ImmutableBytesWritableBijection[Float]
implicit lazy val short2BytesWritable = ImmutableBytesWritableBijection[Short]
implicit lazy val boolean2BytesWritable = ImmutableBytesWritableBijection[Boolean]
implicit lazy val bigDecimal2BytesWritable = ImmutableBytesWritableBijection[BigDecimal]

@implicitNotFound(msg = "Cannot find Bijection type class between ${T} and [Array[Byte] @@ Rep[${T}]")
object ImmutableBytesWritableBijection {
def apply[T](implicit bijection: Bijection[T, Array[Byte] @@ Rep[T]]) = new ImmutableBytesWritableBijection[T](bijection)
}

class ImmutableBytesWritableBijection[@specialized T](bijection: Bijection[T, Array[Byte] @@ Rep[T]]) extends Bijection[T, ImmutableBytesWritable] {
def apply(a: T): ImmutableBytesWritable = new ImmutableBytesWritable(bijection(a))

override def invert(b: ImmutableBytesWritable): T = bijection.invert(Tag[Array[Byte], Rep[T]](b.get()))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.twitter.bijection.hbase

import org.scalacheck.Properties
import com.twitter.bijection.BaseProperties
import HBaseBijections._
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.util.Bytes

/**
* @author Muhammad Ashraf
* @since 7/10/13
*/
object HBaseBijectionsLaws extends Properties("HBaseBijections")
with BaseProperties {


property("String <=> StringBytes") = isInjective[String, StringBytes]
property("Int <=> IntBytes") = isInjective[Int, IntBytes]
property("Long <=> LongBytes") = isInjective[Long, LongBytes]
property("Double <=> DoubleBytes") = isInjective[Double, DoubleBytes]
property("Float <=> FloatBytes") = isInjective[Float, FloatBytes]
property("Boolean <=> BooleanBytes") = isInjective[Boolean, BooleanBytes]
property("Short <=> ShortBytes") = isInjective[Short, ShortBytes]
property("BigDecimal <=> BigDecimalBytes") = isInjective[BigDecimal, BigDecimalBytes]

property("BigDecimal <=> ImmutableBytesWritable") = {
implicit val arbBD = arbitraryViaFn {
bd: BigDecimal => new ImmutableBytesWritable(Bytes.toBytes(bd.underlying()))
}
isBijection[BigDecimal, ImmutableBytesWritable]
}

property("String <=> ImmutableBytesWritable") = {
implicit val arbString = arbitraryViaFn {
input: String => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[String, ImmutableBytesWritable]
}
property("Long <=> ImmutableBytesWritable") = {
implicit val arbLong = arbitraryViaFn {
input: Long => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Long, ImmutableBytesWritable]
}
property("Int <=> ImmutableBytesWritable") = {
implicit val arbInt = arbitraryViaFn {
input: Int => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Int, ImmutableBytesWritable]
}
property("Double <=> ImmutableBytesWritable") = {
implicit val arbDouble = arbitraryViaFn {
input: Double => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Double, ImmutableBytesWritable]
}
property("Float <=> ImmutableBytesWritable") = {
implicit val arbFloat = arbitraryViaFn {
input: Float => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Float, ImmutableBytesWritable]
}
property("Short <=> ImmutableBytesWritable") = {
implicit val arbShort = arbitraryViaFn {
input: Short => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Short, ImmutableBytesWritable]
}
property("Boolean <=> ImmutableBytesWritable") = {
implicit val arbBoolean = arbitraryViaFn {
input: Boolean => new ImmutableBytesWritable(Bytes.toBytes(input))
}
isBijection[Boolean, ImmutableBytesWritable]
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* 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.hbase

import org.specs.Specification
import com.twitter.bijection.{Bijection, BaseProperties}
import HBaseBijections._
import org.apache.hadoop.hbase.io.ImmutableBytesWritable

/**
* @author Muhammad Ashraf
* @since 7/10/13
*/
object HBaseBijectionsSpecifications extends Specification with BaseProperties {

"HBaseBijections" should {
"round trip String -> Array[Byte]" in {
val expected = "Bonjour le monde"
val bytes = Bijection[String, StringBytes](expected)
val result = Bijection.invert[String, StringBytes](bytes)
result must_== expected
}

"round trip Long -> Array[Byte]" in {
val expected = 42L
val bytes = Bijection[Long, LongBytes](expected)
val result = Bijection.invert[Long, LongBytes](bytes)
result must_== expected
}

"round trip Int -> Array[Byte]" in {
val expected = 42
val bytes = Bijection[Int, IntBytes](expected)
val result = Bijection.invert[Int, IntBytes](bytes)
result must_== expected
}

"round trip Double -> Array[Byte]" in {
val expected = 42.0
val bytes = Bijection[Double, DoubleBytes](expected)
val result = Bijection.invert[Double, DoubleBytes](bytes)
result must_== expected
}

"round trip Float -> Array[Byte]" in {
val expected = 42.0F
val bytes = Bijection[Float, FloatBytes](expected)
val result = Bijection.invert[Float, FloatBytes](bytes)
result must_== expected
}

"round trip Short -> Array[Byte]" in {
val expected = 1.toShort
val bytes = Bijection[Short, ShortBytes](expected)
val result = Bijection.invert[Short, ShortBytes](bytes)
result must_== expected
}

"round trip BigDecimal -> Array[Byte]" in {
val expected = BigDecimal(1)
val bytes = Bijection[BigDecimal, BigDecimalBytes](expected)
val result = Bijection.invert[BigDecimal, BigDecimalBytes](bytes)
result must_== expected
}

"round trip Boolean -> Array[Byte]" in {
val expected = true
val bytes = Bijection[Boolean, BooleanBytes](expected)
val result = Bijection.invert[Boolean, BooleanBytes](bytes)
result must_== expected
}

"round trip String -> ImmutableBytesWritable" in {
val expected = "Bonjour le monde"
val bytes = Bijection[String, ImmutableBytesWritable](expected)
val result = Bijection.invert[String, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip Long -> ImmutableBytesWritable" in {
val expected = 1L
val bytes = Bijection[Long, ImmutableBytesWritable](expected)
val result = Bijection.invert[Long, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip Int -> ImmutableBytesWritable" in {
val expected = 42
val bytes = Bijection[Int, ImmutableBytesWritable](expected)
val result = Bijection.invert[Int, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip Double -> ImmutableBytesWritable" in {
val expected = 42.0
val bytes = Bijection[Double, ImmutableBytesWritable](expected)
val result = Bijection.invert[Double, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip Float -> ImmutableBytesWritable" in {
val expected = 42.0F
val bytes = Bijection[Float, ImmutableBytesWritable](expected)
val result = Bijection.invert[Float, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip Short -> ImmutableBytesWritable" in {
val expected = 1.toShort
val bytes = Bijection[Short, ImmutableBytesWritable](expected)
val result = Bijection.invert[Short, ImmutableBytesWritable](bytes)
result must_== expected
}

"round trip BigDecimal -> ImmutableBytesWritable" in {
val expected = BigDecimal(1)
val bytes = Bijection[BigDecimal, ImmutableBytesWritable](expected)
val result = Bijection.invert[BigDecimal, ImmutableBytesWritable](bytes)
result must_== expected
}
}

}
17 changes: 16 additions & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ object BijectionBuild extends Build {
bijectionUtil,
bijectionClojure,
bijectionNetty,
bijectionAvro)
bijectionAvro,
bijectionHbase)

/** No dependencies in bijection other than java + scala */
lazy val bijectionCore = Project(
Expand Down Expand Up @@ -274,4 +275,18 @@ object BijectionBuild extends Build {
"org.apache.avro" % "avro" % "1.7.4"
)
).dependsOn(bijectionCore % "test->test;compile->compile")

lazy val bijectionHbase = Project(
id = "bijection-hbase",
base = file("bijection-hbase"),
settings = sharedSettings
).settings(
name := "bijection-hbase",
previousArtifact := youngestForwardCompatible("hbase"),
osgiExportAll("com.twitter.bijection.hbase"),
libraryDependencies ++= Seq(
"org.apache.hbase" % "hbase" % "0.94.4" % "provided->default",
"org.apache.hadoop" % "hadoop-core" % "1.0.4" % "provided->default"
)
).dependsOn(bijectionCore % "test->test;compile->compile")
}