-
Notifications
You must be signed in to change notification settings - Fork 226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limit number of errors returned (when variables are used) #1034
Limit number of errors returned (when variables are used) #1034
Conversation
implicit um: InputUnmarshaller[In]): Vector[Violation] = { | ||
|
||
// keeping track of the number of errors | ||
var errors = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using mutable variable was the only viable option here to avoid making huge refactoring and keeping the same signature of the original method (by returning Vector[Violation]).
The alternative 1 was to use ListBuffer[Violation] but it would require making signature changes (probably just to return Unit) + it didn't work well with .map(ListValueViolation(0, _, sourceMapper, Nil))
.
The alternative 2 was to propagate the number of errors back to the recursion function but I was not able to make it work properly 🙂
objTpe.fields.toVector.flatMap(f => | ||
isValidValue(f.fieldType, um.getMapValue(valueMap, f.name)) | ||
.map(MapValueViolation(f.name, _, sourceMapper, Nil))) | ||
def isValidValueRec(tpe: InputType[_], in: Option[In])(implicit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a separate recursion function (basically the old method migrated here for the most part) to be called internally so it has easy access to mutable variable
case other => scalar.coerceUserInput(other) | ||
} | ||
case (objTpe: InputObjectType[_], _) => | ||
addViolation( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So instead of returning Vector(violation), we call addViolation(violation)
that mutates number of errors and returns the same Vector(violation)
if (!um.isMapNode(inputVars)) | ||
Failure( | ||
new ExecutionError( | ||
s"Variables should be a map-like object, like JSON object. Got: ${um.render(inputVars)}", | ||
exceptionHandler)) | ||
else { | ||
val res = | ||
definitions.foldLeft(Vector.empty[(String, Either[Vector[Violation], VariableValue])]) { | ||
definitions.foldLeft( | ||
(0, Vector.empty[(String, Either[Vector[Violation], VariableValue])])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed the accumulator's signature from Vector
to (Int, Vector) where Int is to keep track of the number of errors.
We need this change in addition to ValueCoercionHelper.scala, so we can limit the number of errors when multiple
inputs are provided
case Left(violations) => acc :+ (varDef.name -> Left(violations)) | ||
fromScalarMiddleware, | ||
// calculate the allowed number of errors to be returned (if any) | ||
errorsLimit.map(_ - accErrors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
propagate the remaining number of errors that are allowed to be returned
val ctx = new ValidationContext( | ||
schema, | ||
queryAst, | ||
queryAst.sourceMapper, | ||
new TypeInfo(schema), | ||
errorsLimit) | ||
errorsLimitOverride) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would take precedence over RuleBasedQueryValidator.errorsLimit so we could pass and use a single limit via execute
method
@yanns pls take a look when you have time 🙂 |
so that you're not surprised by the delay: |
Hey @yanns, just following up in case you are back 🙂 |
Do you think that we should revert part of the initial PR, and go into that direction: bc-dima-pasieka#2 ? |
Probably yes, it might play better in the long run. Let me update the PR |
@@ -11,7 +11,10 @@ import scala.collection.mutable.{ListBuffer, Map => MutableMap, Set => MutableSe | |||
import scala.reflect.{ClassTag, classTag} | |||
|
|||
trait QueryValidator { | |||
def validateQuery(schema: Schema[_, _], queryAst: ast.Document): Vector[Violation] | |||
def validateQuery( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yanns based on the suggestion from https://github.com/bc-dima-pasieka/sangria/pull/2/files#diff-f36cd7c72002ebd8d7f5fcc1f1b1026e4f54c67bfe9d7268425ba73ecd8a272bL14 - are we ok introducing a breaking change like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR introduces quite a lot of important breaking changes.
I'd suggest that we ignore them for now to focus on the feature.
Once we're happy with the result, we can check how to handle the breaking changes.
You can temporary remove the CI step about breaking changes so that we can focus on the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I commented out a few checks. Let me know what would be the best next steps from here. It seems to be "ready" from my end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good to me.
You can add the exceptions for the binary compatibility checks:
mimaBinaryIssueFilters ++= Seq(
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Executor.apply"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Executor.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Executor.this"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Executor.execute"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Executor.prepare"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.execution.QueryReducerExecutor.reduceQueryWithoutVariables"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.execution.ValueCoercionHelper.isValidValue"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.execution.ValueCoercionHelper.getVariableValue"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.execution.batch.BatchExecutor.executeBatch"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.schema.ResolverBasedAstSchemaBuilder.validateSchema"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.validation.QueryValidator.validateQuery"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"sangria.validation.QueryValidator.validateQuery"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.validation.RuleBasedQueryValidator.validateQuery"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.validation.ValidationContext.this")
),
I've tried to minimize this, but it's a nightmare as the new argument is optional.
The source compatibility is good though.
Can you add those exceptions are enable the binary check again?
modules/core/src/main/scala/sangria/execution/ValueCoercionHelper.scala
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
Use secure configuration by default Follow-up of #1034
Follow up to #1017
The solution from the previous PR works only for cases where input is specified (hardcoded) as a part of the query but doesn't work/executed when variables are used. For example, the following query will still return an unlimited number of errors: