From dc09c5428f5ed1647dbb4186528de3cc8fe719fb Mon Sep 17 00:00:00 2001
From: "P. Thomas Barthelemy"
Date: Mon, 10 Sep 2018 18:17:00 -0700
Subject: [PATCH 1/2] Fixing field builder for passthrough exempt fields.
---
.../ari/graphql/schema/FieldBuilder.scala | 30 ++--
.../schema/NaptimeAnyDataFieldTest.scala | 156 ++++++++++++++++++
.../NaptimePaginatedResourceFieldTest.scala | 1 -
3 files changed, 170 insertions(+), 17 deletions(-)
create mode 100644 naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
diff --git a/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/schema/FieldBuilder.scala b/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/schema/FieldBuilder.scala
index ec3d5c35..bea3426d 100644
--- a/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/schema/FieldBuilder.scala
+++ b/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/schema/FieldBuilder.scala
@@ -138,8 +138,7 @@ object FieldBuilder extends StrictLogging {
Field.apply[SangriaGraphQlContext, DataMapWithParent, Any, Any](
name = FieldBuilder.formatName(fieldName),
fieldType = NaptimeTypes.DataMapType,
- resolve =
- context => context.value.copy(element = context.value.element.getDataMap(fieldName)))
+ resolve = context => context.value.element.getDataMap(fieldName))
// Complex types
case (None, recordDataSchema: RecordDataSchema) =>
@@ -278,24 +277,23 @@ object FieldBuilder extends StrictLogging {
Field.apply[SangriaGraphQlContext, DataMapWithParent, Any, Any](
name = FieldBuilder.formatName(fieldName),
fieldType = sangriaScalarType,
- resolve = context => {
+ resolve = context =>
Option(context.value.element.get(fieldName))
- .map {
- rawValue =>
- val result =
- ValidateDataAgainstSchema.validate(rawValue, dataSchema, validationOptions)
-
- if (result.isValid) {
- result.getFixed match {
- case value: ParseType => value
- case _ => throw ResponseFormatException(s"$fieldName's value is an invalid type")
- }
- } else {
- throw ResponseFormatException(s"$fieldName could not be fixed-up or parsed")
+ .map { rawValue =>
+ val result =
+ ValidateDataAgainstSchema.validate(rawValue, dataSchema, validationOptions)
+
+ if (result.isValid) {
+ result.getFixed match {
+ case value: ParseType => value
+ case _ => throw ResponseFormatException(s"$fieldName's value is an invalid type")
}
+ } else {
+ throw ResponseFormatException(s"$fieldName could not be fixed-up or parsed")
+ }
}
.getOrElse(null)
- })
+ )
}
/**
diff --git a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
new file mode 100644
index 00000000..7cd40b90
--- /dev/null
+++ b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
@@ -0,0 +1,156 @@
+package org.coursera.naptime.ari.graphql.schema
+
+import com.linkedin.data.DataMap
+import com.linkedin.data.schema.RecordDataSchema
+import com.linkedin.data.schema.RecordDataSchema.{Field => RecordDataSchemaField}
+import com.linkedin.data.template.DataTemplateUtil
+import org.coursera.naptime.ResourceName
+import org.coursera.naptime.ResponsePagination
+import org.coursera.naptime.ari.FetcherApi
+import org.coursera.naptime.ari.Response
+import org.coursera.naptime.ari.graphql.Models
+import org.coursera.naptime.ari.graphql.SangriaGraphQlContext
+import org.coursera.naptime.ari.graphql.SangriaGraphQlSchemaBuilder
+import org.coursera.naptime.ari.graphql.helpers.ArgumentBuilder
+import org.coursera.naptime.ari.graphql.marshaller.NaptimeMarshaller._
+import org.coursera.naptime.ari.graphql.models.MergedCourse
+import org.coursera.naptime.ari.graphql.models.MergedInstructor
+import org.coursera.naptime.ari.graphql.models.MergedPartner
+import org.coursera.naptime.ari.graphql.resolvers.NaptimeResolver
+import org.coursera.naptime.ari.graphql.types.NaptimeTypes
+import org.junit.Test
+import org.scalatest.junit.AssertionsForJUnit
+import org.scalatest.mockito.MockitoSugar
+import org.mockito.Matchers.any
+import org.mockito.Mockito.when
+import play.api.libs.json.JsObject
+import sangria.ast.Document
+import sangria.execution.DeprecationTracker
+import sangria.execution.ExecutionPath
+import sangria.execution.Executor
+import sangria.marshalling.ResultMarshaller
+import sangria.parser.QueryParser
+import sangria.schema.Context
+import sangria.schema.Field
+import sangria.schema.ObjectType
+import sangria.schema.Schema
+import sangria.schema.Value
+
+import scala.collection.JavaConverters._
+import scala.concurrent.Await
+import scala.concurrent.ExecutionContext
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+import scala.concurrent.duration.Duration
+
+class NaptimeAnyDataFieldTest extends AssertionsForJUnit with MockitoSugar {
+
+ private[this] val fieldName = "anyDataField"
+
+ private[this] def createContext[Val](value: Val, args: Map[String, Any] = Map("limit" -> 100))(
+ implicit ctxManifest: Manifest[SangriaGraphQlContext],
+ valManifest: Manifest[Val]): Context[SangriaGraphQlContext, Val] = {
+ Context[SangriaGraphQlContext, Val](
+ value = value,
+ ctx = SangriaGraphQlContext(null, null, ExecutionContext.global, debugMode = true),
+ args = ArgumentBuilder.buildArgs(NaptimePaginationField.paginationArguments, args),
+ schema = mock[Schema[SangriaGraphQlContext, Val]],
+ field = mock[Field[SangriaGraphQlContext, Val]],
+ parentType = mock[ObjectType[SangriaGraphQlContext, Any]],
+ marshaller = mock[ResultMarshaller],
+ query = Document.emptyStub,
+ sourceMapper = None,
+ deprecationTracker = DeprecationTracker.empty,
+ astFields = Vector.empty,
+ path = ExecutionPath.empty,
+ deferredResolverState = None)
+ }
+
+ @Test
+ def basic(): Unit = {
+ val passthroughExemptJson =
+ """
+ |{
+ | "name": "PassthroughExempt",
+ | "type": "record",
+ | "passthroughExempt": true,
+ | "fields": [
+ | ]
+ |}
+ """.stripMargin
+ val recordDataSchema =
+ DataTemplateUtil.parseSchema(passthroughExemptJson).asInstanceOf[RecordDataSchema]
+ val field = FieldBuilder.buildField(
+ mock[SchemaMetadata],
+ new RecordDataSchemaField(recordDataSchema),
+ namespace = None,
+ fieldNameOverride = Some(fieldName),
+ resourceName = ResourceName("courses", 1))
+ assert(field.fieldType === NaptimeTypes.DataMapType)
+
+ val dataMap = new DataMap(Map("foo" -> 1).asJava)
+ val context = createContext(
+ DataMapWithParent(new DataMap(Map(fieldName -> dataMap).asJava), null))
+ val result =
+ field.resolve(context).asInstanceOf[Value[SangriaGraphQlContext, DataMap]]
+ assert(result.value === dataMap)
+ }
+
+ @Test
+ def parseDataMapTypes(): Unit = {
+ val schemaTypes = Map(
+ "org.coursera.naptime.ari.graphql.models.MergedCourse" -> MergedCourse.SCHEMA,
+ "org.coursera.naptime.ari.graphql.models.MergedPartner" -> MergedPartner.SCHEMA,
+ "org.coursera.naptime.ari.graphql.models.MergedInstructor" -> MergedInstructor.SCHEMA)
+ val allResources =
+ Set(Models.courseResource, Models.instructorResource, Models.partnersResource)
+ val builder = new SangriaGraphQlSchemaBuilder(allResources, schemaTypes)
+ val schema = builder.generateSchema().data.asInstanceOf[Schema[SangriaGraphQlContext, Any]]
+
+ val query =
+ """
+ |query {
+ | CoursesV1Resource {
+ | get(id: "courseAId") {
+ | id
+ | arbitraryData
+ | }
+ | }
+ |}
+ """.stripMargin
+ val queryAst = QueryParser.parse(query).get
+
+ val fetcher = mock[FetcherApi]
+ val data = List(
+ new DataMap(
+ Map(
+ "arbitraryData" ->
+ new DataMap(Map("moduleOne" -> "abc", "moduleTwo" -> "defg").asJava),
+ "id" -> "courseAId").asJava))
+ when(fetcher.data(any(), any())(any()))
+ .thenReturn(
+ Future.successful(Right(Response(data, ResponsePagination(None, None, None), url = None))))
+
+ val context = SangriaGraphQlContext(fetcher, null, ExecutionContext.global, debugMode = true)
+ val responseData = Await
+ .result(
+ Executor
+ .execute(
+ schema,
+ queryAst,
+ context,
+ variables = JsObject(Map.empty[String, JsObject]),
+ deferredResolver = new NaptimeResolver()),
+ Duration.Inf)
+ .asInstanceOf[JsObject]
+
+ assert(
+ (responseData \ "data" \ "CoursesV1Resource" \ "get" \ "arbitraryData").get
+ .as[Map[String, String]] ===
+ Map("moduleOne" -> "abc", "moduleTwo" -> "defg"))
+ assert(
+ (responseData \ "data" \ "CoursesV1Resource" \ "get" \ "id").get
+ .as[String] === "courseAId")
+ }
+
+}
diff --git a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimePaginatedResourceFieldTest.scala b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimePaginatedResourceFieldTest.scala
index 4f7fb2ae..f9b1a888 100644
--- a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimePaginatedResourceFieldTest.scala
+++ b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimePaginatedResourceFieldTest.scala
@@ -17,7 +17,6 @@
package org.coursera.naptime.ari.graphql.schema
import org.coursera.naptime.ResourceName
-import org.coursera.naptime.ari.Response
import org.coursera.naptime.ari.graphql.Models
import org.coursera.naptime.ari.graphql.SangriaGraphQlContext
import org.coursera.naptime.ari.graphql.helpers.ArgumentBuilder
From 5d72644f40ac1b4b6795cd558c63237c1d0533d2 Mon Sep 17 00:00:00 2001
From: "P. Thomas Barthelemy"
Date: Tue, 11 Sep 2018 10:00:45 -0700
Subject: [PATCH 2/2] Minor tweaks and version bump.
---
.../naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala | 5 +++--
version.sbt | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
index 7cd40b90..ab9b958e 100644
--- a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
+++ b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/schema/NaptimeAnyDataFieldTest.scala
@@ -47,13 +47,14 @@ class NaptimeAnyDataFieldTest extends AssertionsForJUnit with MockitoSugar {
private[this] val fieldName = "anyDataField"
- private[this] def createContext[Val](value: Val, args: Map[String, Any] = Map("limit" -> 100))(
+ private[this] def createContext[Val](value: Val)(
implicit ctxManifest: Manifest[SangriaGraphQlContext],
valManifest: Manifest[Val]): Context[SangriaGraphQlContext, Val] = {
Context[SangriaGraphQlContext, Val](
value = value,
ctx = SangriaGraphQlContext(null, null, ExecutionContext.global, debugMode = true),
- args = ArgumentBuilder.buildArgs(NaptimePaginationField.paginationArguments, args),
+ args =
+ ArgumentBuilder.buildArgs(NaptimePaginationField.paginationArguments, Map("limit" -> 100)),
schema = mock[Schema[SangriaGraphQlContext, Val]],
field = mock[Field[SangriaGraphQlContext, Val]],
parentType = mock[ObjectType[SangriaGraphQlContext, Any]],
diff --git a/version.sbt b/version.sbt
index 0394a72b..1d114b7d 100644
--- a/version.sbt
+++ b/version.sbt
@@ -1 +1 @@
-version in ThisBuild := "0.9.2-alpha17"
+version in ThisBuild := "0.9.2-alpha18"