-
Notifications
You must be signed in to change notification settings - Fork 23
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
Partition calls #591
Partition calls #591
Conversation
…ple routing fields
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.
Nice work 👍
Love the comprehensive test coverage |
* A GraphQL type is considered to be a "mutation payload" (for the purposes of this transform) if | ||
* it has a `success` field of type `Boolean!` plus an `errors` field of type List and any other number | ||
* of fields of type List | ||
*/ |
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 think atlassian public schema defines Payload as
"""
The general shape of a mutation response.
"""
interface Payload {
"Was this mutation successful"
success: Boolean!
"A list of errors if the mutation was not successful"
errors: [MutationError!]
}
would it be reasonable to check if the type extends Payload
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 considered it, but eventually decided not to do it because the type for the use case we're targeting doesn't actually implement Payload
. But you make a good point, that type should really be implementing this interface. They're already adhering to the contract, so it shouldn't be a big change for them 👍
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.
Left some comments, we can address them later too.
In general looks good.
scalarValue: ScalarValue<*>, | ||
inputValueDef: GraphQLInputValueDefinition, | ||
context: Any, | ||
) -> String?, |
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.
Would like to see this made into an interface so it's easier to parse e.g.
interface NadelPartitionKeyExtractor {
fun getPartitionKey(
scalarValue: ScalarValue<*>,
inputValueDef: GraphQLInputValueDefinition,
context: Any,
): String
}
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.
Nice.
import graphql.schema.GraphQLSchema | ||
import graphql.schema.GraphQLTypeUtil | ||
|
||
class NadelFieldPartition( |
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.
Should be internal
so code outside library can't access it.
class NadelPartitionGraphQLErrorException( | ||
message: String, | ||
path: List<Any>? = null, | ||
errorClassification: ErrorClassification? = partitioningErrorClassification, |
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.
Don't think errorClassification
is ever variable, so we should hard code it into the super call i.e.
class NadelPartitionGraphQLErrorException(
message: String,
path: List<Any>? = null,
) : NadelGraphQLErrorException(message, path, partitioningErrorClassification)
import graphql.schema.GraphQLOutputType | ||
import graphql.schema.GraphQLScalarType | ||
|
||
object NadelPartitionListMerger { |
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.
Should be internal
val thisNodesDataCast = thisNodesData?.let { | ||
check(it is List<*>) { "Expected a list, but got ${it::class.simpleName}" } | ||
it | ||
} ?: emptyList<NadelResultInstruction.Set>() |
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.
Are the generics here correct?
Should just be emptyList<Any?>()
right?
) | ||
|
||
if (parentNodes.size != 1) { | ||
// TODO: Support multiple parent nodes (interfaces, unions) |
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.
Multiple parent nodes should only be if it's a list in the result. Don't think abstract types would cause that.
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.
if it's a list in the result
Hm, when would that happen? I'm deailng with fields that have type of List
and parentNodes
is always 1 🤔
return this is GraphQLObjectType | ||
&& this.getField("success")?.let { it.type.unwrapNonNull() as? GraphQLScalarType }?.name == "Boolean" | ||
&& this.getField("errors") != null | ||
&& this.fields.filter { it.name != "success" }.all { it.type.unwrapNonNull() is GraphQLList } |
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.
Could be
&& this.fields.all { it.name == "success" || it.type.unwrapNonNull() is GraphQLList }
Since .filter
and other transform functions return an entire new List
unless the transform is on a Sequence
val parentNode = parentNodes.first() | ||
|
||
val listDataFromPartitionCalls = dataFromPartitionCalls | ||
.mapNotNull { |
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.
Could be
.flatMap {
if (it == null) {
emptyList()
} else {
check(it is List<*>) { "Expected a list, but got ${it::class.simpleName}" }
it
}
}
Also I think that ClassCastException
will print out the expected/actual type. So could just straight up cast it.
.flatMap {
it as List<*>?
}
} | ||
|
||
// TODO: handle HTTP errors | ||
val resultFromPartitionCalls = state.partitionCalls.awaitAll() |
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.
Nice
class NadelFieldPartition( | ||
private val pathToPartitionArg: List<String>, | ||
private val fieldPartitionContext: Any, | ||
private val graphQLSchema: GraphQLSchema, |
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.
Maybe be explicit about it being the engineSchema
since there's a few schema objects.
Thanks for the great suggestions 🙏 I'll merge it as is to unblock subsequent changes quickly and raise follow-up PRs to address your feedback. |
Please make sure you consider the following: