Skip to content

Commit

Permalink
Add scalafmt plugin and apply to project (#246)
Browse files Browse the repository at this point in the history
* Add scalafmt plugin and apply to project

* Address comments

* Address comments
  • Loading branch information
cliu587 committed May 2, 2018
1 parent 62379bb commit fae3a22
Show file tree
Hide file tree
Showing 130 changed files with 3,885 additions and 3,009 deletions.
13 changes: 13 additions & 0 deletions .scalafmt.conf
@@ -0,0 +1,13 @@
maxColumn = 100
docstrings = JavaDoc

align {
openParenCallSite = false
openParenDefnSite = false
}

runner {
optimizer {
forceConfigStyleOnOffset = -1
}
}
2 changes: 2 additions & 0 deletions build.sbt
Expand Up @@ -3,3 +3,5 @@ scalaVersion in ThisBuild := "2.12.4"
crossScalaVersions in ThisBuild := Seq("2.11.11", "2.12.4")

organization in ThisBuild := "org.coursera.naptime"

scalafmtOnCompile in ThisBuild := true
Expand Up @@ -58,8 +58,9 @@ trait GraphqlSchemaProvider {
*
* @param schemaProvider A schema provider.
*/
class DefaultGraphqlSchemaProvider @Inject() (schemaProvider: SchemaProvider)
extends GraphqlSchemaProvider with StrictLogging {
class DefaultGraphqlSchemaProvider @Inject()(schemaProvider: SchemaProvider)
extends GraphqlSchemaProvider
with StrictLogging {
private[this] var fullSchema = FullSchema.empty
private[this] var cachedSchema: Schema[SangriaGraphQlContext, Any] =
DefaultGraphqlSchemaProvider.EMPTY_SCHEMA
Expand All @@ -75,17 +76,22 @@ class DefaultGraphqlSchemaProvider @Inject() (schemaProvider: SchemaProvider)
.get(resource.mergedType)
.map(mergedType => Right(resource.mergedType -> mergedType))
.getOrElse {
logger.info(s"Did not find merged type `${resource.mergedType}` for resource " +
s"${resource.name}.v${resource.version.getOrElse(0L)}")
val resourceName = ResourceName(resource.name, resource.version.getOrElse(0L).toInt)
logger.info(
s"Did not find merged type `${resource.mergedType}` for resource " +
s"${resource.name}.v${resource.version.getOrElse(0L)}")
val resourceName =
ResourceName(resource.name, resource.version.getOrElse(0L).toInt)
Left(MissingMergedType(resourceName))
}
}
val types = typesAndErrors.flatMap(_.right.toOption).toMap
try {
val builder = new SangriaGraphQlSchemaBuilder(latestSchema.resources, types)
val builder =
new SangriaGraphQlSchemaBuilder(latestSchema.resources, types)
val schemaAndErrors = builder.generateSchema()
val graphQlSchema = schemaAndErrors.data.asInstanceOf[Schema[SangriaGraphQlContext, Any]].copy(additionalTypes = sangria.schema.BuiltinScalars)
val graphQlSchema = schemaAndErrors.data
.asInstanceOf[Schema[SangriaGraphQlContext, Any]]
.copy(additionalTypes = sangria.schema.BuiltinScalars)
fullSchema = latestSchema
cachedSchema = graphQlSchema

Expand All @@ -94,7 +100,7 @@ class DefaultGraphqlSchemaProvider @Inject() (schemaProvider: SchemaProvider)
case NonFatal(e) =>
logger.error(s"Could not build schema.", e)
fullSchema = latestSchema
// Note: we do not update cachedSchema, but instead retain the existing schema.
// Note: we do not update cachedSchema, but instead retain the existing schema.
}
}

Expand Down Expand Up @@ -127,4 +133,3 @@ object DefaultGraphqlSchemaProvider {
additionalTypes = sangria.schema.BuiltinScalars)

}

Expand Up @@ -30,43 +30,45 @@ import sangria.schema.Value
import sangria.schema.Field
import sangria.schema.ObjectType

class SangriaGraphQlSchemaBuilder(
resources: Set[Resource],
schemas: Map[String, RecordDataSchema])
extends StrictLogging {
class SangriaGraphQlSchemaBuilder(resources: Set[Resource], schemas: Map[String, RecordDataSchema])
extends StrictLogging {

val schemaMetadata = SchemaMetadata(resources, schemas)

/**
* Generates a GraphQL schema for the provided set of resources to this class
* Returns a "root" object that has one field available for each Naptime Resource provided.
*
* @return a Sangria GraphQL Schema with all resources defined,
* and a list of errors that came up while generating the schema
*/
* Generates a GraphQL schema for the provided set of resources to this class
* Returns a "root" object that has one field available for each Naptime Resource provided.
*
* @return a Sangria GraphQL Schema with all resources defined,
* and a list of errors that came up while generating the schema
*/
def generateSchema(): WithSchemaErrors[Schema[SangriaGraphQlContext, DataMap]] = {
val topLevelResourceObjectsAndErrors = resources.map { resource =>
val lookupTypeAndErrors =
NaptimeTopLevelResourceField.generateLookupTypeForResource(resource, schemaMetadata)
val fields = lookupTypeAndErrors.data.flatMap { resourceObject =>
if (resourceObject.fields.nonEmpty) {
Some(Field.apply[SangriaGraphQlContext, DataMap, DataMap, Any](
NaptimeTopLevelResourceField.formatResourceTopLevelName(resource),
resourceObject,
resolve = (_: Context[SangriaGraphQlContext, DataMap]) => {
Value(new DataMap())
}))
Some(
Field.apply[SangriaGraphQlContext, DataMap, DataMap, Any](
NaptimeTopLevelResourceField.formatResourceTopLevelName(resource),
resourceObject,
resolve = (_: Context[SangriaGraphQlContext, DataMap]) => {
Value(new DataMap())
}
))
} else {
None
}
}
lookupTypeAndErrors.copy(data = fields)
}

val topLevelResourceObjects = topLevelResourceObjectsAndErrors.flatMap(_.data)
val topLevelResourceObjects =
topLevelResourceObjectsAndErrors.flatMap(_.data)
val schemaErrors = topLevelResourceObjectsAndErrors.foldLeft(SchemaErrors.empty)(_ ++ _.errors)

val dedupedResources = topLevelResourceObjects.groupBy(_.name).map(_._2.head).toList
val dedupedResources =
topLevelResourceObjects.groupBy(_.name).map(_._2.head).toList
val rootObject = ObjectType[SangriaGraphQlContext, DataMap](
name = "root",
description = "Top-level accessor for Naptime resources",
Expand Down
Expand Up @@ -53,51 +53,50 @@ import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.util.Failure
import scala.util.Success


@Singleton
class GraphQLController @Inject() (
class GraphQLController @Inject()(
graphqlSchemaProvider: GraphqlSchemaProvider,
schemaProvider: GraphqlSchemaProvider,
fetcher: FetcherApi,
filterList: FilterList,
metricsCollector: GraphQLMetricsCollector)
(implicit ec: ExecutionContext)
extends InjectedController
with StrictLogging {
metricsCollector: GraphQLMetricsCollector)(implicit ec: ExecutionContext)
extends InjectedController
with StrictLogging {

def renderSchema = Action {
Ok(SchemaRenderer.renderSchema(graphqlSchemaProvider.schema))
}

def graphqlBody: Action[JsValue] = Action.async(parse.json) { request =>

val query = (request.body \ "query").as[String]
val operation = (request.body \ "operationName").asOpt[String]

val variables = (request.body \ "variables").toOption.flatMap {
case JsString(vars) => Some(parseVariables(vars))
case obj: JsObject => Some(obj)
case _ => None
}.getOrElse(Json.obj())
val variables = (request.body \ "variables").toOption
.flatMap {
case JsString(vars) => Some(parseVariables(vars))
case obj: JsObject => Some(obj)
case _ => None
}
.getOrElse(Json.obj())

executeQuery(query, request, variables, operation).map { res =>
Ok(res.response)
}
}

def graphqlBatch: Action[JsValue] = Action.async(parse.json) { request =>

val queries = request.body.as[List[JsObject]]
val resultsFut = Future.traverse(queries) { queryObj =>
val query = (queryObj \ "query").as[String]
val operation = (queryObj \ "operationName").asOpt[String]

val variables = (queryObj \ "variables").toOption.flatMap {
case JsString(vars) => Some(parseVariables(vars))
case obj: JsObject => Some(obj)
case _ => None
}.getOrElse(Json.obj())
val variables = (queryObj \ "variables").toOption
.flatMap {
case JsString(vars) => Some(parseVariables(vars))
case obj: JsObject => Some(obj)
case _ => None
}
.getOrElse(Json.obj())

executeQuery(query, request, variables, operation)
}
Expand Down Expand Up @@ -128,33 +127,36 @@ class GraphQLController @Inject() (
}
parsedQuery match {
case Success(queryAst) =>
val baseFilter: IncomingQuery => Future[OutgoingQuery] = (incoming: IncomingQuery) => {
val context = SangriaGraphQlContext(fetcher, requestHeader, ec, incoming.debugMode)
Executor.execute(
graphqlSchemaProvider.schema,
queryAst,
context,
variables = variables,
middleware = List(
new ResponseMetadataMiddleware(),
metricsCollectionMiddleware,
new SlowLogMiddleware(logger, incoming.debugMode)),
exceptionHandler = GraphQLController.exceptionHandler(logger),
deferredResolver = naptimeResolver)
.map { executionResponse =>
OutgoingQuery(executionResponse.as[JsObject], Some(Response.empty))
}
}.recover {
case error: QueryAnalysisError =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: ErrorWithResolver =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: Exception =>
logger.error("GraphQL execution error", error)
OutgoingQuery(Json.obj("errors" -> Json.arr(error.getMessage)), None)
}
val incomingQuery = IncomingQuery(
queryAst, requestHeader, variables, operation, debugMode = false)
val baseFilter: IncomingQuery => Future[OutgoingQuery] =
(incoming: IncomingQuery) => {
val context = SangriaGraphQlContext(fetcher, requestHeader, ec, incoming.debugMode)
Executor
.execute(
graphqlSchemaProvider.schema,
queryAst,
context,
variables = variables,
middleware = List(
new ResponseMetadataMiddleware(),
metricsCollectionMiddleware,
new SlowLogMiddleware(logger, incoming.debugMode)),
exceptionHandler = GraphQLController.exceptionHandler(logger),
deferredResolver = naptimeResolver
)
.map { executionResponse =>
OutgoingQuery(executionResponse.as[JsObject], Some(Response.empty))
}
}.recover {
case error: QueryAnalysisError =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: ErrorWithResolver =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: Exception =>
logger.error("GraphQL execution error", error)
OutgoingQuery(Json.obj("errors" -> Json.arr(error.getMessage)), None)
}
val incomingQuery =
IncomingQuery(queryAst, requestHeader, variables, operation, debugMode = false)

val filterFn = filterList.filters.reverse.foldLeft(baseFilter) {
case (accumulatedFilters, filter) =>
Expand All @@ -171,7 +173,10 @@ class GraphQLController @Inject() (
"locations" -> Json.arr(
Json.obj(
"line" -> error.originalError.position.line,
"column" -> error.originalError.position.column))), None))
"column" -> error.originalError.position.column))
),
None
))

case Failure(error) =>
throw error
Expand All @@ -184,9 +189,9 @@ object GraphQLController {
def exceptionHandler(logger: Logger): ExceptionHandler = {
// TODO(bryan): Check superuser status here before returning message
ExceptionHandler(onException = {
case (m, e: Exception) =>
logger.error("Uncaught query execution error", e)
HandledException(e.getMessage)
case (m, e: Exception) =>
logger.error("Uncaught query execution error", e)
HandledException(e.getMessage)
})
}
}
Expand Up @@ -4,8 +4,8 @@ import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DefaultFilters @Inject() (
queryComplexityFilter: QueryComplexityFilter)
extends FilterList(List(
queryComplexityFilter
))
class DefaultFilters @Inject()(queryComplexityFilter: QueryComplexityFilter)
extends FilterList(
List(
queryComplexityFilter
))
Expand Up @@ -9,4 +9,3 @@ trait Filter {
def apply(nextFilter: FilterFn): FilterFn

}

Expand Up @@ -24,42 +24,39 @@ import scala.concurrent.ExecutionContext
import scala.concurrent.Future

@Singleton
class QueryComplexityFilter @Inject() (
class QueryComplexityFilter @Inject()(
graphqlSchemaProvider: GraphqlSchemaProvider,
configuration: ComplexityFilterConfiguration)
(implicit executionContext: ExecutionContext)
extends Filter
with Results
with StrictLogging {
configuration: ComplexityFilterConfiguration)(implicit executionContext: ExecutionContext)
extends Filter
with Results
with StrictLogging {

val MAX_COMPLEXITY = configuration.maxComplexity

def apply(nextFilter: FilterFn): FilterFn = { incoming =>
computeComplexity(incoming.document, incoming.variables).flatMap { complexity =>
if (complexity > MAX_COMPLEXITY) {
Future.successful(
OutgoingQuery(
response = Json.obj(
"error" -> "Query is too complex.",
"complexity" -> complexity),
ariResponse = None))
} else {
nextFilter.apply(incoming)
computeComplexity(incoming.document, incoming.variables)
.flatMap { complexity =>
if (complexity > MAX_COMPLEXITY) {
Future.successful(
OutgoingQuery(
response = Json.obj("error" -> "Query is too complex.", "complexity" -> complexity),
ariResponse = None))
} else {
nextFilter.apply(incoming)
}
}
.recover {
case error: QueryAnalysisError =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: ErrorWithResolver =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: Exception =>
OutgoingQuery(Json.obj("errors" -> Json.arr(error.getMessage)), None)
}
}.recover {
case error: QueryAnalysisError =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: ErrorWithResolver =>
OutgoingQuery(error.resolveError.as[JsObject], None)
case error: Exception =>
OutgoingQuery(Json.obj("errors" -> Json.arr(error.getMessage)), None)
}
}

private[graphql] def computeComplexity(
queryAst: Document,
variables: JsObject)
(implicit executionContext: ExecutionContext): Future[Double] = {
private[graphql] def computeComplexity(queryAst: Document, variables: JsObject)(
implicit executionContext: ExecutionContext): Future[Double] = {
// TODO(bryan): is there a way around this var?
var complexity = 0D
val complReducer = QueryReducer.measureComplexity[SangriaGraphQlContext] { (c, ctx) =>
Expand All @@ -73,7 +70,8 @@ class QueryComplexityFilter @Inject() (
variables = variables,
exceptionHandler = GraphQLController.exceptionHandler(logger),
queryReducers = List(complReducer),
deferredResolver = new NoopResolver())
deferredResolver = new NoopResolver()
)

executorFut.map { _ =>
complexity
Expand Down

0 comments on commit fae3a22

Please sign in to comment.