Skip to content

Commit

Permalink
Clean up code and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gnawf committed May 6, 2024
1 parent 28522e4 commit 5a6a908
Show file tree
Hide file tree
Showing 11 changed files with 769 additions and 127 deletions.
3 changes: 2 additions & 1 deletion lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ dependencies {
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")

testImplementation("org.slf4j:slf4j-simple:$slf4jVersion")
testImplementation("com.fasterxml.jackson.core:jackson-databind:2.15.3")
testImplementation("org.openjdk.jmh:jmh-core:1.37")
testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.37")

Expand All @@ -44,6 +43,8 @@ dependencies {
testImplementation("io.mockk:mockk:1.13.8")

testImplementation("com.tngtech.archunit:archunit:1.2.1")

testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.0")
}

// compileJava.source file("build/generated-src"), sourceSets.main.java
Expand Down
123 changes: 0 additions & 123 deletions lib/src/main/java/graphql/nadel/NadelResultTracker.kt

This file was deleted.

2 changes: 2 additions & 0 deletions lib/src/main/java/graphql/nadel/NextgenEngine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import graphql.nadel.instrumentation.parameters.NadelInstrumentationOnErrorParam
import graphql.nadel.instrumentation.parameters.NadelInstrumentationTimingParameters.ChildStep.Companion.DocumentCompilation
import graphql.nadel.instrumentation.parameters.NadelInstrumentationTimingParameters.RootStep
import graphql.nadel.instrumentation.parameters.child
import graphql.nadel.result.NadelResultMerger
import graphql.nadel.result.NadelResultTracker
import graphql.nadel.util.OperationNameUtil
import graphql.normalized.ExecutableNormalizedField
import graphql.normalized.ExecutableNormalizedOperationFactory.createExecutableNormalizedOperationWithRawVariables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import graphql.ExecutionInput
import graphql.GraphQLContext
import graphql.execution.instrumentation.InstrumentationState
import graphql.nadel.NadelExecutionHints
import graphql.nadel.NadelResultTracker
import graphql.nadel.Service
import graphql.nadel.ServiceExecutionHydrationDetails
import graphql.nadel.engine.instrumentation.NadelInstrumentationTimer
import graphql.nadel.hooks.CreateServiceContextParams
import graphql.nadel.hooks.NadelExecutionHooks
import graphql.nadel.result.NadelResultTracker
import graphql.normalized.ExecutableNormalizedOperation
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ fun <T> List<T>.subListOrNull(fromIndex: Int, toIndex: Int): List<T>? {
return subList(fromIndex = fromIndex, toIndex = toIndex)
}

fun <T, R> Iterable<T>.foldWhileNotNull(initial: R?, operation: (acc: R, T) -> R): R? {
fun <T, R> Iterable<T>.foldWhileNotNull(initial: R?, operation: (acc: R, T) -> R?): R? {
var accumulator = initial ?: return null
for (element in this) {
accumulator = operation(accumulator, element) ?: return null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package graphql.nadel
package graphql.nadel.result

import graphql.ExecutionResult
import graphql.ExecutionResultImpl
import graphql.GraphQLError
import graphql.introspection.Introspection
import graphql.nadel.ServiceExecutionResult
import graphql.nadel.engine.transform.query.NadelFieldAndService
import graphql.nadel.engine.transform.result.NadelResultKey
import graphql.nadel.engine.util.AnyMap
Expand Down
35 changes: 35 additions & 0 deletions lib/src/main/java/graphql/nadel/result/NadelResultPathBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package graphql.nadel.result

internal interface NadelResultPathBuilder {
fun add(key: String): NadelResultPathBuilder
fun add(index: Int): NadelResultPathBuilder
fun build(): List<NadelResultPathSegment>

companion object {
operator fun invoke(
path: List<NadelResultPathSegment> = emptyList(),
): NadelResultPathBuilder {
return object : NadelResultPathBuilder {
private var segments = path.toMutableList()

override fun add(key: String): NadelResultPathBuilder {
segments.add(NadelResultPathSegment.Object(key))
return this
}

override fun add(index: Int): NadelResultPathBuilder {
segments.add(NadelResultPathSegment.Array(index))
return this
}

override fun build(): List<NadelResultPathSegment> {
return segments
}
}
}
}
}

internal fun List<NadelResultPathSegment>.toBuilder(): NadelResultPathBuilder {
return NadelResultPathBuilder(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package graphql.nadel.result

internal sealed interface NadelResultPathSegment {
@JvmInline
value class Object(val key: String) : NadelResultPathSegment

@JvmInline
value class Array(val index: Int) : NadelResultPathSegment
}
154 changes: 154 additions & 0 deletions lib/src/main/java/graphql/nadel/result/NadelResultTracker.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package graphql.nadel.result

import graphql.ExecutionResult
import graphql.incremental.DelayedIncrementalPartialResult
import graphql.nadel.engine.transform.query.NadelQueryPath
import graphql.nadel.engine.transform.result.json.JsonNode
import graphql.nadel.engine.util.AnyList
import graphql.nadel.engine.util.AnyMap
import kotlinx.coroutines.CompletableDeferred

/**
* todo: this needs to track multiple responses
*/
internal class NadelResultTracker {
private val result = CompletableDeferred<ExecutionResult>()

private enum class NavigationOutcome {
QueuedChild,
ExpandedArray,
DeadEnd,
}

suspend fun getResultPath(
queryPath: NadelQueryPath,
node: JsonNode,
): List<NadelResultPathSegment>? {
val result = result.await()
val data = result.getData<Any?>()

val queryPathSegments = queryPath.segments
val currentResultPathSegments = mutableListOf<NadelResultPathSegment>()
val currentQueryPathSegments = mutableListOf<String>()

val queue = mutableListOf<Any?>(data)

fun printState(): String {
return """
Current query path: ${
currentQueryPathSegments.joinToString(
separator = ",",
prefix = "[",
postfix = "]"
)
}
Current result path: ${
currentResultPathSegments.joinToString(
separator = ",",
prefix = "[",
postfix = "]"
)
}
""".replaceIndent(' '.toString().repeat(n = 4))
}

println(
"Trying to find $node from ${
queryPath.segments.joinToString(
separator = ",",
prefix = "[",
postfix = "]"
)
}"
)

while (queue.isNotEmpty()) {
val element = queue.removeLast()
println("Visiting $element")
if (element === node.value) {
println("Got em $currentResultPathSegments")
return currentResultPathSegments
}

val outcome: NavigationOutcome = when (element) {
is AnyList -> {
if (element.isNotEmpty()) {
queue.addAll(element)
currentResultPathSegments.add(NadelResultPathSegment.Array(element.lastIndex))
NavigationOutcome.ExpandedArray
} else {
NavigationOutcome.DeadEnd
}
}
is AnyMap -> {
if (currentQueryPathSegments.size < queryPathSegments.size) {
val nextQueryPathSegment = queryPathSegments[currentQueryPathSegments.size]
val nextElement = element[nextQueryPathSegment]

if (nextElement == null) {
NavigationOutcome.DeadEnd // todo: tests
} else {
queue.add(nextElement)
currentResultPathSegments.add(NadelResultPathSegment.Object(nextQueryPathSegment))
currentQueryPathSegments.add(nextQueryPathSegment)
NavigationOutcome.QueuedChild
}
} else {
NavigationOutcome.DeadEnd // todo: tests
}
}
else -> NavigationOutcome.DeadEnd // todo: tests
}

when (outcome) {
NavigationOutcome.QueuedChild -> {
}
NavigationOutcome.ExpandedArray -> {
}
NavigationOutcome.DeadEnd -> {
if (queue.isNotEmpty()) { // i.e. we have other array elements to visit
while (currentResultPathSegments.isNotEmpty()) {
val last = currentResultPathSegments.lastOrNull() ?: break

when (last) {
is NadelResultPathSegment.Array -> {
if (last.index == 0) {
// Nothing more to visit in the array, remember that we traverse end -> front
println("Popping dead end array")
currentResultPathSegments.removeLast()
} else {
println("Moving to next array element ${last.index - 1}")
// We're moving to the next element
currentResultPathSegments[currentResultPathSegments.lastIndex] =
NadelResultPathSegment.Array(last.index - 1)
// Nothing further to fix, stop
break
}
}
is NadelResultPathSegment.Object -> {
println("Popping up dead end object")
currentResultPathSegments.removeLast()
currentQueryPathSegments.removeLast()
}
}
}
}
}
}

println("Loop end\n${printState()}")
}

println("Didn't get em")
return null
}

fun complete(value: ExecutionResult) {
result.complete(value)
}

fun complete(value: DelayedIncrementalPartialResult) {
// result.complete(value)
// todo: track here
}
}
5 changes: 5 additions & 0 deletions lib/src/test/kotlin/graphql/nadel/Jackson.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package graphql.nadel

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

val jsonObjectMapper = jacksonObjectMapper()
Loading

0 comments on commit 5a6a908

Please sign in to comment.