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

[WIP] Add deferred executions to rename transform #559

2 changes: 1 addition & 1 deletion lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
id("com.bnorm.power.kotlin-power-assert")
}

val graphqlJavaVersion = "0.0.0-2024-04-30T01-25-21-2f5ff3c"
val graphqlJavaVersion = "0.0.0-2024-06-28T04-37-51-99ec596"
val slf4jVersion = "1.7.25"

dependencies {
Expand Down
23 changes: 22 additions & 1 deletion lib/src/main/java/graphql/nadel/NextgenEngine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.future.asCompletableFuture
import kotlinx.coroutines.future.asDeferred
import kotlinx.coroutines.future.await
Expand Down Expand Up @@ -269,7 +270,10 @@ internal class NextgenEngine(
service = service,
transformedQuery = transformedQuery,
executionContext = executionContext,
executionPlan = executionPlan,
executionHydrationDetails = executionContext.hydrationDetails,
artificialFields = queryTransform.artificialFields,
overallToUnderlyingFields = queryTransform.overallToUnderlyingFields,
)
}
val transformedResult: ServiceExecutionResult = when {
Expand All @@ -293,7 +297,10 @@ internal class NextgenEngine(
service: Service,
transformedQuery: ExecutableNormalizedField,
executionContext: NadelExecutionContext,
executionPlan: NadelExecutionPlan,
executionHydrationDetails: ServiceExecutionHydrationDetails? = null,
artificialFields: List<ExecutableNormalizedField>,
overallToUnderlyingFields: Map<ExecutableNormalizedField, List<ExecutableNormalizedField>>,
): ServiceExecutionResult {
val timer = executionContext.timer

Expand Down Expand Up @@ -361,7 +368,21 @@ internal class NextgenEngine(

if (serviceExecResult is NadelIncrementalServiceExecutionResult) {
executionContext.incrementalResultSupport.defer(
serviceExecResult.incrementalItemPublisher.asFlow()
serviceExecResult.incrementalItemPublisher
.asFlow()
.map {
// Transform
resultTransformer
.transform(
executionContext = executionContext,
executionPlan = executionPlan,
artificialFields = artificialFields,
overallToUnderlyingFields = overallToUnderlyingFields,
service = service,
result = serviceExecResult
)
it
}
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ internal class NadelDeepRenameTransform : NadelTransform<NadelDeepRenameTransfor
queryPathToField = deepRename.queryPathToField,
fieldArguments = field.normalizedArguments,
fieldChildren = transformer.transform(field.children),
deferredExecutions = field.deferredExecutions
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ internal class NadelRenameTransform : NadelTransform<State> {
queryPathToField = NadelQueryPath(listOf(rename.underlyingName)),
fieldArguments = field.normalizedArguments,
fieldChildren = transformer.transform(field.children),
deferredExecutions = field.deferredExecutions
)
)
}
Expand Down
12 changes: 12 additions & 0 deletions lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package graphql.nadel.engine.transform.query

import graphql.normalized.ExecutableNormalizedField
import graphql.normalized.NormalizedInputValue
import graphql.normalized.incremental.NormalizedDeferredExecution
import graphql.schema.GraphQLInterfaceType
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLOutputType
import graphql.schema.GraphQLSchema
import graphql.schema.GraphQLTypeUtil
import kotlin.collections.LinkedHashSet

object NFUtil {
// Exists for IntelliJ search everywhere purposes, DO NOT INVOKE
Expand All @@ -18,6 +20,7 @@ object NFUtil {
pathToField: NadelQueryPath,
fieldArguments: Map<String, NormalizedInputValue>,
fieldChildren: List<ExecutableNormalizedField>,
deferredExecutions: LinkedHashSet<NormalizedDeferredExecution> = LinkedHashSet(),
): List<ExecutableNormalizedField> {
return createFieldRecursively(
schema,
Expand All @@ -26,6 +29,7 @@ object NFUtil {
fieldArguments,
fieldChildren,
pathToFieldIndex = 0,
deferredExecutions
)
}

Expand All @@ -35,6 +39,7 @@ object NFUtil {
queryPathToField: NadelQueryPath,
fieldArguments: Map<String, NormalizedInputValue>,
fieldChildren: List<ExecutableNormalizedField>,
deferredExecutions: LinkedHashSet<NormalizedDeferredExecution> = LinkedHashSet(),
): ExecutableNormalizedField {
return createParticularField(
schema,
Expand All @@ -43,6 +48,7 @@ object NFUtil {
fieldArguments,
fieldChildren,
pathToFieldIndex = 0,
deferredExecutions
)
}

Expand All @@ -53,6 +59,7 @@ object NFUtil {
fieldArguments: Map<String, NormalizedInputValue>,
fieldChildren: List<ExecutableNormalizedField>,
pathToFieldIndex: Int,
deferredExecutions: LinkedHashSet<NormalizedDeferredExecution>,
): List<ExecutableNormalizedField> {
// Note: remember that we are creating fields that do not exist in the original NF
// Thus, we need to handle interfaces and object types
Expand All @@ -65,6 +72,7 @@ object NFUtil {
fieldArguments,
fieldChildren,
pathToFieldIndex,
deferredExecutions
)
}
is GraphQLObjectType -> listOf(
Expand All @@ -75,6 +83,7 @@ object NFUtil {
fieldArguments,
fieldChildren,
pathToFieldIndex,
deferredExecutions
)
)
else -> error("Unsupported type '${parentType.javaClass.name}'")
Expand All @@ -88,6 +97,7 @@ object NFUtil {
fieldArguments: Map<String, NormalizedInputValue>,
fieldChildren: List<ExecutableNormalizedField>,
pathToFieldIndex: Int,
deferredExecutions: LinkedHashSet<NormalizedDeferredExecution>,
): ExecutableNormalizedField {
val fieldName = queryPathToField.segments[pathToFieldIndex]
val fieldDef = parentType.getFieldDefinition(fieldName)
Expand All @@ -96,6 +106,7 @@ object NFUtil {
return ExecutableNormalizedField.newNormalizedField()
.objectTypeNames(listOf(parentType.name))
.fieldName(fieldName)
.deferredExecutions(deferredExecutions)
.also { builder ->
if (pathToFieldIndex == queryPathToField.segments.lastIndex) {
builder.normalizedArguments(fieldArguments)
Expand All @@ -112,6 +123,7 @@ object NFUtil {
fieldArguments,
fieldChildren,
pathToFieldIndex = pathToFieldIndex + 1,
deferredExecutions
)
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package graphql.nadel.engine.transform.result

import graphql.incremental.DelayedIncrementalPartialResultImpl
import graphql.nadel.NadelIncrementalServiceExecutionResult
import graphql.nadel.Service
import graphql.nadel.ServiceExecutionResult
import graphql.nadel.engine.NadelExecutionContext
import graphql.nadel.engine.blueprint.NadelOverallExecutionBlueprint
import graphql.nadel.engine.plan.NadelExecutionPlan
import graphql.nadel.engine.transform.query.NadelQueryPath
import graphql.nadel.engine.transform.result.json.JsonNodes
import graphql.nadel.engine.util.JsonMap
import graphql.nadel.engine.util.MutableJsonMap
Expand All @@ -14,6 +17,8 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.reactive.asFlow

internal class NadelResultTransformer(private val executionBlueprint: NadelOverallExecutionBlueprint) {
suspend fun transform(
Expand All @@ -24,11 +29,47 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera
service: Service,
result: ServiceExecutionResult,
): ServiceExecutionResult {
//NadelIncrementalServiceExecutionResult -> IncrementalItemPublisher.map (apply transforms to every itme in publisher)
//result
if (result is NadelIncrementalServiceExecutionResult) {
result.incrementalItemPublisher.asFlow()
.map {
val incremental = it.incremental
?.map {

}
DelayedIncrementalPartialResultImpl.newIncrementalExecutionResult()

.extensions(it.extensions)
.build()
}
}
// maybe here or in NextGenEngine
val nodes = JsonNodes(result.data)

val deferredInstructions = ArrayList<Deferred<List<NadelResultInstruction>>>()

nodes.getNodesAt(NadelQueryPath(listOf("issue", "user")))

val asyncInstructions = ArrayList<Deferred<List<NadelResultInstruction>>>()

// issue {
// ... @defer {
// user {
// name # @renamed(from: "asdfaiowjefwef")
// }
// }
// key # @renamed(from: "asdf")
// }
// "incremtanl": [
// {
// "data": {
// "user": {
// name: "Steven"
// }
// }
// "path": [issue]
// }
// ]
coroutineScope {
// transform step of field [issue -> user -> name]
for ((field, steps) in executionPlan.transformationSteps) {
// This can be null if we did not end up sending the field e.g. for hydration
val underlyingFields = overallToUnderlyingFields[field]
Expand All @@ -37,7 +78,7 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera
}

for (step in steps) {
deferredInstructions.add(
asyncInstructions.add(
async {
step.transform.getResultInstructions(
executionContext,
Expand All @@ -54,14 +95,14 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera
}
}

deferredInstructions.add(
asyncInstructions.add(
async {
getRemoveArtificialFieldInstructions(artificialFields, nodes)
},
)
}

val instructions = deferredInstructions
val instructions = asyncInstructions
.awaitAll()
.flatten()

Expand Down
72 changes: 38 additions & 34 deletions lib/src/main/java/graphql/nadel/validation/NadelUnionValidation.kt
Original file line number Diff line number Diff line change
@@ -1,45 +1,49 @@
package graphql.nadel.validation

import graphql.nadel.validation.NadelSchemaValidationError.UnionHasExtraType
import graphql.nadel.validation.util.NadelSchemaUtil
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLUnionType

internal class NadelUnionValidation(
private val typeValidation: NadelTypeValidation,
) {
fun validate(
schemaElement: NadelServiceSchemaElement,
): List<NadelSchemaValidationError> {
return emptyList()
return if (schemaElement.overall is GraphQLUnionType && schemaElement.underlying is GraphQLUnionType) {
schemaElement.overall.types
.flatMap { memberOverallType ->
val memberUnderlyingType =
NadelSchemaUtil.getUnderlyingType(memberOverallType, schemaElement.service)

// return if (schemaElement.overall is GraphQLUnionType && schemaElement.underlying is GraphQLUnionType) {
// schemaElement.overall.types
// .flatMap { unionOverallType ->
// val unionUnderlyingType = NadelSchemaUtil.getUnderlyingType(unionOverallType, schemaElement.service)
//
// if (!schemaElement.underlying.types.contains(unionUnderlyingType)) {
// listOf(
// UnionHasExtraType(
// service = schemaElement.service,
// unionType = schemaElement.overall,
// extraType = unionOverallType as GraphQLObjectType,
// ),
// )
// } else if (unionUnderlyingType == null) {
// listOf(
// MissingUnderlyingType(
// service = schemaElement.service,
// overallType = unionOverallType,
// ),
// )
// } else {
// typeValidation.validate(
// NadelServiceSchemaElement(
// service = schemaElement.service,
// overall = unionOverallType,
// underlying = unionUnderlyingType,
// ),
// )
// }
// }
// } else {
// emptyList()
// }
if (memberUnderlyingType == null) {
listOf(
NadelSchemaValidationError.MissingUnderlyingType(
service = schemaElement.service,
overallType = memberOverallType,
),
)
} else if (!schemaElement.underlying.types.contains(memberUnderlyingType)) {
listOf(
UnionHasExtraType(
service = schemaElement.service,
unionType = schemaElement.overall,
extraType = memberOverallType as GraphQLObjectType,
),
)
} else {
typeValidation.validate(
NadelServiceSchemaElement(
service = schemaElement.service,
overall = memberOverallType,
underlying = memberUnderlyingType,
),
)
}
}
} else {
emptyList()
}
}
}
Loading
Loading