Skip to content
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

Support single source ID in new batch hydrator #473

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,16 @@ internal class NadelNewBatchHydrator(
fieldName = state.hydratedField.name,
)

val fieldSource = instructions
.first()
.actorInputValueDefs
.asSequence()
.map {
it.valueSource
}
.singleOfType<ValueSource.FieldResultValue>()

return if (executionBlueprint.engineSchema.getField(coords)!!.type.unwrapNonNull().isList) {
val fieldSource = instructions
.first()
.actorInputValueDefs
.asSequence()
.map {
it.valueSource
}
.singleOfType<ValueSource.FieldResultValue>()

// todo: move this to validation
instructions
Expand All @@ -261,7 +262,18 @@ internal class NadelNewBatchHydrator(
sourceId to instruction
}
} else {
throw UnsupportedOperationException("todo")
// todo: determine what to do here in the longer term, this hook should probably be replaced
val instruction = state.executionContext.hooks.getHydrationInstruction(
instructions = instructions,
parentNode = parentNode,
aliasHelper = state.aliasHelper,
userContext = state.executionContext.userContext,
)!!

extractValues(parentNode, fieldSource, state.aliasHelper)
.map { sourceId ->
sourceId to instruction
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package graphql.nadel.tests.hooks

import graphql.nadel.Nadel
import graphql.nadel.NadelExecutionHints
import graphql.nadel.engine.blueprint.NadelGenericHydrationInstruction
import graphql.nadel.engine.blueprint.hydration.NadelHydrationActorInputDef.ValueSource
import graphql.nadel.engine.transform.artificial.NadelAliasHelper
import graphql.nadel.engine.transform.result.json.JsonNode
import graphql.nadel.engine.transform.result.json.JsonNodeExtractor
import graphql.nadel.engine.util.singleOfType
import graphql.nadel.hooks.NadelExecutionHooks
import graphql.nadel.tests.EngineTestHook
import graphql.nadel.tests.UseHook

@UseHook
class `new-batching-single-source-id` : EngineTestHook {
override fun makeExecutionHints(builder: NadelExecutionHints.Builder): NadelExecutionHints.Builder {
return super.makeExecutionHints(builder)
.newBatchHydrationGrouping { true }
}

override fun makeNadel(builder: Nadel.Builder): Nadel.Builder {
return super.makeNadel(builder)
.executionHooks(
object : NadelExecutionHooks {
override fun <T : NadelGenericHydrationInstruction> getHydrationInstruction(
instructions: List<T>,
parentNode: JsonNode,
aliasHelper: NadelAliasHelper,
userContext: Any?,
): T? {
return instructions
.single { instruction ->
val fieldSource = instruction.actorInputValueDefs
.asSequence()
.map {
it.valueSource
}
.singleOfType<ValueSource.FieldResultValue>()

val sourceNodes = JsonNodeExtractor.getNodesAt(
parentNode,
aliasHelper.getQueryPath(fieldSource.queryPathToField)
)
val sourceIdType = (sourceNodes.single().value as String).substringBefore("/")

instruction.actorService.name.startsWith(sourceIdType)
}
}
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
name: "new batching single source id"
enabled: true
overallSchema:
# language=GraphQL
activity: |
type Query {
activity: [Activity]
}
union ActivityContent = Issue | Comment
type Activity {
id: ID!
contentId: ID!
content: ActivityContent
@hydrated(
service: "comments"
field: "commentsByIds"
arguments: [
{name: "ids" value: "$source.contentId"}
]
)
@hydrated(
service: "issues"
field: "issuesByIds"
arguments: [
{name: "ids" value: "$source.contentId"}
]
)
}
# language=GraphQL
issues: |
type Query {
issuesByIds(ids: [ID!]!): [Issue!]
}
type Issue {
id: ID!
title: String
}
# language=GraphQL
comments: |
type Query {
commentsByIds(ids: [ID!]!): [Comment!]
}
type Comment {
id: ID!
content: String
}
underlyingSchema:
# language=GraphQL
activity: |
type Query {
activity: [Activity]
}
type Activity {
id: ID!
contentId: ID!
}
# language=GraphQL
issues: |
type Query {
issuesByIds(ids: [ID!]!): [Issue!]
}
type Issue {
id: ID!
title: String
}
# language=GraphQL
comments: |
type Query {
commentsByIds(ids: [ID!]!): [Comment!]
}
type Comment {
id: ID!
content: String
}
# language=GraphQL
query: |
{
activity {
content {
__typename
... on Issue {
id
title
}
... on Comment {
id
content
}
}
}
}
variables: { }
serviceCalls:
- serviceName: "activity"
request:
# language=GraphQL
query: |
{
activity {
__typename__batch_hydration__content: __typename
batch_hydration__content__contentId: contentId
batch_hydration__content__contentId: contentId
}
}
variables: { }
# language=JSON
response: |-
{
"data": {
"activity": [
{
"__typename__batch_hydration__content": "Activity",
"batch_hydration__content__contentId": "issue/4000"
},
{
"__typename__batch_hydration__content": "Activity",
"batch_hydration__content__contentId": "issue/8080"
},
{
"__typename__batch_hydration__content": "Activity",
"batch_hydration__content__contentId": "issue/7496"
},
{
"__typename__batch_hydration__content": "Activity",
"batch_hydration__content__contentId": "comment/1234"
}
]
},
"extensions": {}
}
- serviceName: "issues"
request:
# language=GraphQL
query: |
{
issuesByIds(ids: ["issue/4000", "issue/8080", "issue/7496"]) {
__typename
id
batch_hydration__content__id: id
title
}
}
variables: { }
# language=JSON
response: |-
{
"data": {
"issuesByIds": [
{
"__typename": "Issue",
"id": "issue/4000",
"batch_hydration__content__id": "issue/4000",
"title": "Four Thousand"
},
{
"__typename": "Issue",
"id": "issue/8080",
"batch_hydration__content__id": "issue/8080",
"title": "Eighty Eighty"
},
{
"__typename": "Issue",
"id": "issue/7496",
"batch_hydration__content__id": "issue/7496",
"title": "Seven Four Nine Six"
}
]
},
"extensions": {}
}
- serviceName: "comments"
request:
# language=GraphQL
query: |
{
commentsByIds(ids: ["comment/1234"]) {
__typename
content
id
batch_hydration__content__id: id
}
}
variables: { }
# language=JSON
response: |-
{
"data": {
"commentsByIds": [
{
"__typename": "Comment",
"id": "comment/1234",
"batch_hydration__content__id": "comment/1234",
"content": "One Two Three Four"
}
]
},
"extensions": {}
}
# language=JSON
response: |-
{
"data": {
"activity": [
{
"content": {
"__typename": "Issue",
"id": "issue/4000",
"title": "Four Thousand"
}
},
{
"content": {
"__typename": "Issue",
"id": "issue/8080",
"title": "Eighty Eighty"
}
},
{
"content": {
"__typename": "Issue",
"id": "issue/7496",
"title": "Seven Four Nine Six"
}
},
{
"content": {
"__typename": "Comment",
"id": "comment/1234",
"content": "One Two Three Four"
}
}
]
},
"errors": []
}
Loading