diff --git a/dataset/src/main/scala/frameless/ops/AggregateTypes.scala b/dataset/src/main/scala/frameless/ops/AggregateTypes.scala index e46a0eff..403c2530 100644 --- a/dataset/src/main/scala/frameless/ops/AggregateTypes.scala +++ b/dataset/src/main/scala/frameless/ops/AggregateTypes.scala @@ -3,6 +3,15 @@ package ops import shapeless._ +/** A type class to extract the column types out of an HList of [[frameless.TypedAggregate]]. + * + * @note This type class is mostly a workaround to issue with slow implicit derivation for Comapped. + * @example + * {{{ + * type U = TypedAggregate[T,A] :: TypedAggregate[T,B] :: TypedAggregate[T,C] :: HNil + * type Out = A :: B :: C :: HNil + * }}} + */ trait AggregateTypes[V, U <: HList] { type Out <: HList } @@ -12,8 +21,8 @@ object AggregateTypes { implicit def deriveHNil[T]: AggregateTypes.Aux[T, HNil, HNil] = new AggregateTypes[T, HNil] { type Out = HNil } - implicit def deriveCons1[V, H, TT <: HList, T <: HList]( - implicit tail: AggregateTypes.Aux[V, TT, T] - ): AggregateTypes.Aux[V, TypedAggregate[V, H] :: TT, H :: T] = - new AggregateTypes[V, TypedAggregate[V, H] :: TT] {type Out = H :: T} + implicit def deriveCons1[T, H, TT <: HList, V <: HList]( + implicit tail: AggregateTypes.Aux[T, TT, V] + ): AggregateTypes.Aux[T, TypedAggregate[T, H] :: TT, H :: V] = + new AggregateTypes[T, TypedAggregate[T, H] :: TT] {type Out = H :: V} } diff --git a/dataset/src/main/scala/frameless/ops/ColumnTypes.scala b/dataset/src/main/scala/frameless/ops/ColumnTypes.scala index fb4d6c83..e5ae6aea 100644 --- a/dataset/src/main/scala/frameless/ops/ColumnTypes.scala +++ b/dataset/src/main/scala/frameless/ops/ColumnTypes.scala @@ -3,17 +3,26 @@ package ops import shapeless._ -trait ColumnTypes[V, U <: HList] { +/** A type class to extract the column types out of an HList of [[frameless.TypedColumn]]. + * + * @note This type class is mostly a workaround to issue with slow implicit derivation for Comapped. + * @example + * {{{ + * type U = TypedColumn[T,A] :: TypedColumn[T,B] :: TypedColumn[T,C] :: HNil + * type Out = A :: B :: C :: HNil + * }}} + */ +trait ColumnTypes[T, U <: HList] { type Out <: HList } object ColumnTypes { - type Aux[V, U <: HList, Out0 <: HList] = ColumnTypes[V, U] {type Out = Out0} + type Aux[T, U <: HList, Out0 <: HList] = ColumnTypes[T, U] {type Out = Out0} implicit def deriveHNil[T]: ColumnTypes.Aux[T, HNil, HNil] = new ColumnTypes[T, HNil] { type Out = HNil } - implicit def deriveCons[V, H, TT <: HList, T <: HList]( - implicit tail: ColumnTypes.Aux[V, TT, T] - ): ColumnTypes.Aux[V, TypedColumn[V, H] :: TT, H :: T] = - new ColumnTypes[V, TypedColumn[V, H] :: TT] {type Out = H :: T} + implicit def deriveCons[T, H, TT <: HList, V <: HList]( + implicit tail: ColumnTypes.Aux[T, TT, V] + ): ColumnTypes.Aux[T, TypedColumn[T, H] :: TT, H :: V] = + new ColumnTypes[T, TypedColumn[T, H] :: TT] {type Out = H :: V} } diff --git a/dataset/src/test/scala/frameless/ops/ColumnTypesTest.scala b/dataset/src/test/scala/frameless/ops/ColumnTypesTest.scala new file mode 100644 index 00000000..303eb2cb --- /dev/null +++ b/dataset/src/test/scala/frameless/ops/ColumnTypesTest.scala @@ -0,0 +1,27 @@ +package frameless +package ops + +import org.scalacheck.Prop +import org.scalacheck.Prop.forAll +import shapeless.HNil +import shapeless.:: + +class ColumnTypesTest extends TypedDatasetSuite { + test("test summoning") { + def prop[A: TypedEncoder, B: TypedEncoder, C: TypedEncoder, D: TypedEncoder](data: Vector[X4[A, B, C, D]]): Prop = { + val d: TypedDataset[X4[A, B, C, D]] = TypedDataset.create(data) + val hlist = d('a) :: d('b) :: d('c) :: d('d) :: HNil + + type TC[N] = TypedColumn[X4[A,B,C,D], N] + + type IN = TC[A] :: TC[B] :: TC[C] :: TC[D] :: HNil + type OUT = A :: B :: C :: D :: HNil + + implicitly[ColumnTypes.Aux[X4[A,B,C,D], IN, OUT]] + Prop.passed // successful compilation implies test correctness + } + + check(forAll(prop[Int, String, X1[String], Boolean] _)) + check(forAll(prop[Vector[Int], Vector[Vector[String]], X1[String], Option[String]] _)) + } +}