From 4b6c7cc314b462a2f9073c00023e1bd077f003ee Mon Sep 17 00:00:00 2001 From: otto-dev Date: Tue, 2 Jul 2019 11:04:55 +1000 Subject: [PATCH 1/2] Default JSON encoder for Scala case classes and tuples --- docs/src/main/tut/04_library_scala.md | 15 +-------------- .../main/scala/mist/api/encoding/JsEncoder.scala | 3 +++ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/docs/src/main/tut/04_library_scala.md b/docs/src/main/tut/04_library_scala.md index 175252949..5820635ff 100644 --- a/docs/src/main/tut/04_library_scala.md +++ b/docs/src/main/tut/04_library_scala.md @@ -296,6 +296,7 @@ It supports: - Unit - primitives: Short, Int, Long, Float, String, Double, Boolean - collections: Array, Seq, Map +- Case classes - experimental: DataFrame, DataSet - *Warning* - return them only if you sure that they are small, otherwise it will lead to `OutOfMemory` ```scala import mist.api.encoding.spark._ @@ -331,20 +332,6 @@ class Foo(val a: Int, val b: String) val fooEnc: JsEncoder[Foo] = JsEncoder(foo => JsMap("a" -> foo.a.js, "b" -> foo.b.js)) ``` -Also it's possible to automatically derive an encoder for case classes: -```tut:silent -import mist.api._ -import mist.api.encoding -import mist.api.encoding._ -import mist.api.encoding.defaults._ - -case class Bar(a: Int, b: String) -case class Foo(x: Int, foos: Seq[Bar]) - -implicit val barEnc: JsEncoder[Bar] = encoding.generic.encoder[Bar] -implicit val fooEnc: JsEncoder[Foo] = encoding.generic.encoder[Foo] -``` - #### Validation For example for calculating pi using dartboard method n should be at least positive number. diff --git a/mist-lib/src/main/scala/mist/api/encoding/JsEncoder.scala b/mist-lib/src/main/scala/mist/api/encoding/JsEncoder.scala index 48b6900b1..a8aa25176 100644 --- a/mist-lib/src/main/scala/mist/api/encoding/JsEncoder.scala +++ b/mist-lib/src/main/scala/mist/api/encoding/JsEncoder.scala @@ -1,6 +1,7 @@ package mist.api.encoding import mist.api.data._ +import shadedshapeless.Lazy import scala.annotation.implicitNotFound @@ -36,6 +37,8 @@ trait defaultEncoders { case None => JsNull } implicit def mapEnc[A](implicit enc: JsEncoder[A]): JsEncoder[Map[String, A]] = JsEncoder(m => JsMap(m.mapValues(enc.apply))) + + implicit def productEnc[A <: Product](implicit enc: Lazy[ObjectEncoder[A]]): JsEncoder[A] = JsEncoder(enc.value.apply) } object defaultEncoders extends defaultEncoders From d385c5c6686a62eabac30586d43760c723c67009 Mon Sep 17 00:00:00 2001 From: otto-dev Date: Tue, 2 Jul 2019 11:49:15 +1000 Subject: [PATCH 2/2] Default JSON extractor for Scala case classes and tuples --- docs/src/main/tut/04_library_scala.md | 3 --- .../src/main/scala/mist/api/encoding/JsExtractor.scala | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/main/tut/04_library_scala.md b/docs/src/main/tut/04_library_scala.md index 5820635ff..dbfa2804d 100644 --- a/docs/src/main/tut/04_library_scala.md +++ b/docs/src/main/tut/04_library_scala.md @@ -153,9 +153,6 @@ import org.apache.spark.SparkContext case class Foo(a: Int, b: String) object ComplexRootArgFn extends MistFn { - - implicit val fooExt: RootExtractor[Foo] = encoding.generic.extractor[Foo] - // expected input is json: // { // "a": 42, diff --git a/mist-lib/src/main/scala/mist/api/encoding/JsExtractor.scala b/mist-lib/src/main/scala/mist/api/encoding/JsExtractor.scala index 3d85a1386..67f119f09 100644 --- a/mist-lib/src/main/scala/mist/api/encoding/JsExtractor.scala +++ b/mist-lib/src/main/scala/mist/api/encoding/JsExtractor.scala @@ -2,6 +2,7 @@ package mist.api.encoding import mist.api._ import mist.api.data._ +import shadedshapeless.Lazy import scala.annotation.implicitNotFound import scala.reflect.ClassTag @@ -134,6 +135,12 @@ trait defaultExtractors { case value => Failed.invalidType(s"Map[String, ${ext.`type`}]", value.toString) } + + implicit def productExtWithDefaults[A <: Product](implicit + ext: Lazy[ObjectExtractor[A]], + patcher: Lazy[DefaultsPatcher[A]] + ): RootExtractor[A] = + RootExtractor[A](ext.value.`type`)(js => ext.value.apply(patcher.value.apply(js))) }