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

Boosting Spark to 2.1.0. Adding tests that include Java types encoded … #105

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
val sparkVersion = "2.0.2"
val sparkVersion = "2.1.0"
val catsv = "0.9.0"
val scalatest = "3.0.1"
val shapeless = "2.3.2"
Expand Down
8 changes: 6 additions & 2 deletions core/src/main/scala/frameless/Injection.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package frameless

/** An Injection[A, B] is a reverible function from A to B.
import scala.annotation.implicitNotFound

/** An Injection[A, B] is a reversible function from A to B.
*
* Must obey `forAll { a: A => invert(apply(a)) == a }`.
*/
@implicitNotFound(msg = "Cannot find Injection from ${A} to ${B}. Try bringing Frameless' implicit Injections in scope via 'import frameless.implicits.injections._'")
trait Injection[A, B] extends Serializable {
def apply(a: A): B
def invert(b: B): A
}

object Injection {
def apply[A, B]()(implicit i: Injection[A,B]): Injection[A, B] = i
def apply[A, B](f: A => B, g: B => A): Injection[A, B] = new Injection[A, B] {
def apply(a: A): B = f(a)
def invert(b: B): A = g(b)
}
}
}
8 changes: 8 additions & 0 deletions dataset/src/main/scala/frameless/implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,12 @@ object implicits {
// implicit def floatToDouble[T](col: TypedColumn[T, Float]): TypedColumn[T, Double] = col.cast[Double]
// implicit def floatToBigDecimal[T](col: TypedColumn[T, Float]): TypedColumn[T, BigDecimal] = col.cast[BigDecimal]
}

object injections {
implicit val javaBoolean: Injection[java.lang.Boolean, Boolean] = Injection(a => a, b => b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DId you consider Injection[java.lang.Boolean, Option[Boolean]]? Often when I see Java boxed primitives, it's Java-style Scala code using nulls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I didn't think about this. From what I tested, using Optional here doesn't come for free in terms of extra code being generated. My main goal with the Java types here was for completeness and and enrich some of the tests.

implicit val javaInt: Injection[java.lang.Integer, Int] = Injection(a => a, b => b)
implicit val javaDouble: Injection[java.lang.Double, Double] = Injection(a => a, b => b)
implicit val javaFloat: Injection[java.lang.Float, Float] = Injection(a => a, b => b)
implicit val javaLong: Injection[java.lang.Long, Long] = Injection(a => a, b => b)
}
}
6 changes: 5 additions & 1 deletion dataset/src/test/scala/frameless/CollectTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import org.scalacheck.Prop._
import scala.reflect.ClassTag

class CollectTests extends TypedDatasetSuite {
import implicits.injections._

test("collect()") {
check(forAll(prop[X2[Int, Int]] _))
check(forAll(prop[X2[String, String]] _))
Expand Down Expand Up @@ -38,7 +40,9 @@ class CollectTests extends TypedDatasetSuite {
check(forAll(prop[Option[SQLDate]] _))
check(forAll(prop[Option[SQLTimestamp]] _))

check(forAll(prop[Vector[Int]] _))
check(forAll(prop[Vector[Boolean]] _))
check(forAll(prop[Vector[java.lang.Boolean]] _))
check(forAll(prop[Vector[(java.lang.Float, Option[java.lang.Long])]] _))
check(forAll(prop[Option[Int]] _))
check(forAll(prop[Vector[X2[Int, Int]]] _))

Expand Down
2 changes: 1 addition & 1 deletion dataset/src/test/scala/frameless/InjectionTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ object Food {
)
}

// Supposingly coming from a java lib, shapeless can't derive stuff for this one :(
// Supposedly coming from a java lib, shapeless can't derive stuff for this one :(
class LocalDateTime {
var instant: Long = _

Expand Down
19 changes: 18 additions & 1 deletion dataset/src/test/scala/frameless/TypedDatasetSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package frameless
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession
import org.scalactic.anyvals.PosZInt
import org.scalacheck.Arbitrary
import org.scalatest.FunSuite
import org.scalatest.prop.Checkers

class TypedDatasetSuite extends FunSuite with Checkers {
class TypedDatasetSuite extends FunSuite with Checkers with JavaTypeArbitraries {
// Limit size of generated collections and number of checks because Travis
implicit override val generatorDrivenConfig =
PropertyCheckConfiguration(sizeRange = PosZInt(10), minSize = PosZInt(10))
Expand All @@ -23,3 +24,19 @@ class TypedDatasetSuite extends FunSuite with Checkers {
implicit def sc = session.sparkContext
implicit def sqlContext = session.sqlContext
}

trait JavaTypeArbitraries {
import implicits.injections._

implicit val arbitraryJavaBoolean =
Arbitrary(Arbitrary.arbitrary[Boolean].map(Injection[java.lang.Boolean, Boolean].invert))
implicit val arbitraryJavaInteger =
Arbitrary(Arbitrary.arbitrary[Int].map(Injection[java.lang.Integer, Int].invert))
implicit val arbitraryJavaLong =
Arbitrary(Arbitrary.arbitrary[Long].map(Injection[java.lang.Long, Long].invert))
implicit val arbitraryJavaDouble =
Arbitrary(Arbitrary.arbitrary[Double].map(Injection[java.lang.Double, Double].invert))
implicit val arbitraryJavaFloat =
Arbitrary(Arbitrary.arbitrary[Float].map(Injection[java.lang.Float, Float].invert))
}

3 changes: 2 additions & 1 deletion dataset/src/test/scala/frameless/functions/UdfTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class UdfTests extends TypedDatasetSuite {
(dataset21 ?= d) && (dataset22 ?= d)
}

check(forAll(prop[Int, Int, Int] _))
check(forAll(prop[Vector[X4[Long, X1[Int], Vector[X2[X1[Long], Vector[X1[Int]]]], Long]], Vector[Int],
X3[X1[Long], Vector[Char], String]] _))
check(forAll(prop[String, Int, Int] _))
}

Expand Down