From 7e0880257431d19db7ae7c9106b517b5ba24e92c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 9 Aug 2018 08:07:31 +0300 Subject: [PATCH] #32 start writing JsonPath dsl --- .../main/scala/tethys/readers/JsonPath.scala | 32 +++++++++++ .../instances/SingleValueObjectReader.scala | 54 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 modules/core/src/main/scala/tethys/readers/JsonPath.scala create mode 100644 modules/core/src/main/scala/tethys/readers/instances/SingleValueObjectReader.scala diff --git a/modules/core/src/main/scala/tethys/readers/JsonPath.scala b/modules/core/src/main/scala/tethys/readers/JsonPath.scala new file mode 100644 index 00000000..f9ac3751 --- /dev/null +++ b/modules/core/src/main/scala/tethys/readers/JsonPath.scala @@ -0,0 +1,32 @@ +package tethys.readers + +import tethys.JsonReader +import tethys.readers.JsonPath.JsonObjectPart +import tethys.readers.instances.SingleValueObjectReader + +import scala.language.dynamics + + +sealed trait JsonPath extends Dynamic { + def as[A](implicit reader: JsonReader[A]): JsonReader[A] = buildReader(reader) + def array() + + def selectDynamic(name: String): JsonObjectPart = new JsonObjectPart(name, this) + def applyDynamic(index: Int): JsonObjectPart = ??? + + protected def buildReader[A](inner: JsonReader[A]): JsonReader[A] +} + + +object JsonPath extends JsonPath { + + override protected def buildReader[A](inner: JsonReader[A]): JsonReader[A] = inner + + final class JsonObjectPart(name: String, outer: JsonPath) extends JsonPath { + override protected def buildReader[A](inner: JsonReader[A]): JsonReader[A] = { + outer.buildReader(new SingleValueObjectReader[A](name, inner)) + } + } + + +} diff --git a/modules/core/src/main/scala/tethys/readers/instances/SingleValueObjectReader.scala b/modules/core/src/main/scala/tethys/readers/instances/SingleValueObjectReader.scala new file mode 100644 index 00000000..8e1c901d --- /dev/null +++ b/modules/core/src/main/scala/tethys/readers/instances/SingleValueObjectReader.scala @@ -0,0 +1,54 @@ +package tethys.readers.instances + +import tethys.JsonReader +import tethys.readers.tokens.TokenIterator +import tethys.readers.{FieldName, ReaderError} + +import scala.annotation.tailrec +import scala.reflect.ClassTag + +class SingleValueObjectReader[A: ClassTag](name: String, reader: JsonReader[A]) extends JsonReader[A] { + + + override def read(it: TokenIterator)(implicit fieldName: FieldName): A = { + if(!it.currentToken().isObjectStart) ReaderError.wrongType[A] + else readField(it) + } + + @tailrec + private def readField(it: TokenIterator)(implicit fieldName: FieldName): A = { + it.currentToken() match { + case token if token.isObjectEnd => + it.nextToken() + reader.defaultValue.getOrElse(ReaderError.wrongJson(s"'$name' field is missing")) + case token if token.isFieldName => + val currentName = it.fieldName() + it.nextToken() + if(currentName == name) { + val res = reader.read(it)(fieldName.appendFieldName(name)) + skipRest(it) + res + } else { + readField(it) + } + + case token => ReaderError.wrongJson(s"Expect end of object or field name but '$token' found") + } + } + + @tailrec + private def skipRest(it: TokenIterator)(implicit fieldName: FieldName): Unit = { + it.currentToken() match { + case token if token.isObjectEnd => + it.nextToken() + + case token if token.isFieldName => + it.nextToken() + it.skipExpression() + skipRest(it) + + case token => + ReaderError.wrongJson(s"Expect end of object or field name but '$token' found") + } + } +}