Repository: apollographql/apollo-kotlin
Pull request #4739 (2023-03-08 13:11:32)

Use Kotlin 1.8.20-RC

netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *apollo-android-docs* processing.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 43a306156b2fd8a8cfc5864057aea500c4b935a7 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/apollo-android-docs/deploys/64088987f6682d0007b1eea8 |

Patch:
diff --git a/gradle/libraries.toml b/gradle/libraries.toml
index 6cbc400e08..90c41b16d0 100644
--- a/gradle/libraries.toml
+++ b/gradle/libraries.toml
@@ -15,8 +15,8 @@ javaPoet = "1.13.0"
 jetbrains-annotations = "23.0.0"
 junit = "4.13.2"
 kotlin-plugin-min = "1.6.0"
-kotlin-plugin = "1.8.20-RC-257"
-kotlin-plugin-max = "1.8.20-RC-257"
+kotlin-plugin = "1.8.20-RC"
+kotlin-plugin-max = "1.8.20-RC"
 kotlin-stdlib = "1.6.21"
 kotlinx-coroutines = "1.6.4"
 kotlinx-datetime = "0.4.0"
diff --git a/gradle/repositories.gradle.kts b/gradle/repositories.gradle.kts
index 6a6c833446..8f91177fba 100644
--- a/gradle/repositories.gradle.kts
+++ b/gradle/repositories.gradle.kts
@@ -1,8 +1,7 @@
 listOf(pluginManagement.repositories, dependencyResolutionManagement.repositories).forEach {
   it.apply {
-    maven {
-      url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/")
-    }
+    // Uncomment this one to use the Kotlin "dev" repository
+    // maven { url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/") }
     mavenCentral()
 
     exclusiveContent {
diff --git a/intellij-plugin/build.gradle.kts b/intellij-plugin/build.gradle.kts
index d299224c1f..1fd992480f 100644
--- a/intellij-plugin/build.gradle.kts
+++ b/intellij-plugin/build.gradle.kts
@@ -15,9 +15,8 @@ plugins {
 
 // XXX: this should use the settings repositories instead
 repositories {
-  maven {
-    url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/")
-  }
+  // Uncomment this one to use the Kotlin "dev" repository
+  // maven { url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/") }
   mavenCentral()
 }
 
diff --git a/libraries/apollo-runtime/api/apollo-runtime.api b/libraries/apollo-runtime/api/apollo-runtime.api
index 9c2586740f..454805449f 100644
--- a/libraries/apollo-runtime/api/apollo-runtime.api
+++ b/libraries/apollo-runtime/api/apollo-runtime.api
@@ -303,8 +303,6 @@ public final class com/apollographql/apollo3/network/http/HttpNetworkTransport :
 	public fun dispose ()V
 	public fun execute (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
 	public final fun execute (Lcom/apollographql/apollo3/api/ApolloRequest;Lcom/apollographql/apollo3/api/http/HttpRequest;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lkotlinx/coroutines/flow/Flow;
-	public final fun getEngine ()Lcom/apollographql/apollo3/network/http/HttpEngine;
-	public final fun getExposeErrorBody ()Z
 	public final fun getInterceptors ()Ljava/util/List;
 	public final fun newBuilder ()Lcom/apollographql/apollo3/network/http/HttpNetworkTransport$Builder;
 }
diff --git a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
index f4aaa1db26..410df1b669 100644
--- a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
+++ b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/network/http/HttpNetworkTransport.kt
@@ -28,13 +28,15 @@ import kotlinx.coroutines.flow.filterNot
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
+import okio.use
 
 class HttpNetworkTransport
 private constructor(
     private val httpRequestComposer: HttpRequestComposer,
-    val engine: HttpEngine,
+    private val engine: HttpEngine,
     val interceptors: List<HttpInterceptor>,
-    val exposeErrorBody: Boolean,
+    private val exposeErrorBody: Boolean,
 ) : NetworkTransport {
   private val engineInterceptor = EngineInterceptor()
 
@@ -151,22 +153,65 @@ private constructor(
       customScalarAdapters: CustomScalarAdapters,
       httpResponse: HttpResponse,
   ): Flow<ApolloResponse<D>> {
-    val jsonMerger = DeferredJsonMerger()
+    var jsonMerger: DeferredJsonMerger? = null
+
     return multipartBodyFlow(httpResponse)
-        .map { part ->
+        .mapNotNull { part ->
           try {
-            val merged = jsonMerger.merge(part)
-            val deferredFragmentIds = jsonMerger.mergedFragmentIds
-            val isLast = !jsonMerger.hasNext
-            operation.parseJsonResponse(
-                jsonReader = merged.jsonReader(),
-                customScalarAdapters = customScalarAdapters.withDeferredFragmentIds(deferredFragmentIds)
-            ).newBuilder().isLast(isLast).build()
+            val what = part.peek().jsonReader().use { reader ->
+              // detect what kind of payload we have
+              reader.beginObject()
+              if (!reader.hasNext()) {
+                return@use EMPTY
+              }
+              val name = reader.nextName()
+
+              if (name == "payload") {
+                return@use PAYLOAD
+              } else {
+                return@use OTHER
+              }
+            }
+
+            when (what)  {
+              EMPTY -> {
+                // nothing to do
+                null
+              }
+              PAYLOAD -> {
+                val reader = part.jsonReader()
+                // advance the reader
+                reader.beginObject()
+                reader.nextName()
+                operation.parseJsonResponse(
+                    jsonReader = reader,
+                    customScalarAdapters = customScalarAdapters
+                ).newBuilder().build()
+              }
+              else -> {
+                if (jsonMerger == null) {
+                  jsonMerger = DeferredJsonMerger()
+                }
+                val merged = jsonMerger!!.merge(part)
+                val deferredFragmentIds = jsonMerger!!.mergedFragmentIds
+                val isLast = !jsonMerger!!.hasNext
+
+                if (jsonMerger!!.isEmptyPayload) {
+                  null
+                } else {
+                  operation.parseJsonResponse(
+                      jsonReader = merged.jsonReader(),
+                      customScalarAdapters = customScalarAdapters.withDeferredFragmentIds(deferredFragmentIds)
+                  ).newBuilder().isLast(isLast).build()
+                }
+              }
+            }
+
           } catch (e: Exception) {
             errorResponse(operation, e)
           }
         }
-        .filterNot { jsonMerger.isEmptyPayload }
+
   }
 
   private fun <D : Operation.Data> ApolloResponse<D>.withHttpInfo(
@@ -276,4 +321,10 @@ private constructor(
       )
     }
   }
+
+  private companion object {
+    private const val EMPTY = 0
+    private const val PAYLOAD = 1
+    private const val OTHER = 2
+  }
 }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 937bdc6d4a..a3a1404e52 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,4 @@
-// TODO: See https://youtrack.jetbrains.com/issue/KT-56536
-//rootProject.name = "apollo-kotlin"
+rootProject.name = "apollo-kotlin"
 
 rootProject.projectDir
     .resolve("libraries")
@@ -33,4 +32,4 @@ gradleEnterprise {
     val isCiBuild = System.getenv("CI") != null
     isUploadInBackground = !isCiBuild
   }
-}
\ No newline at end of file
+}


Test patch:
diff --git a/tests/multipart/build.gradle.kts b/tests/multipart/build.gradle.kts
index b778b3dc3d..bc0cc8c193 100644
--- a/tests/multipart/build.gradle.kts
+++ b/tests/multipart/build.gradle.kts
@@ -26,7 +26,12 @@ kotlin {
 
 
 apollo {
-  service("service") {
+  service("mockserver") {
+    sourceFolder.set("mockserver")
     packageName.set("multipart")
   }
+  service("router") {
+    sourceFolder.set("router")
+    packageName.set("router")
+  }
 }
diff --git a/tests/multipart/src/commonMain/graphql/operations.graphql b/tests/multipart/src/commonMain/graphql/mockserver/operations.graphql
similarity index 100%
rename from tests/multipart/src/commonMain/graphql/operations.graphql
rename to tests/multipart/src/commonMain/graphql/mockserver/operations.graphql
diff --git a/tests/multipart/src/commonMain/graphql/schema.graphqls b/tests/multipart/src/commonMain/graphql/mockserver/schema.graphqls
similarity index 100%
rename from tests/multipart/src/commonMain/graphql/schema.graphqls
rename to tests/multipart/src/commonMain/graphql/mockserver/schema.graphqls
diff --git a/tests/multipart/src/commonMain/graphql/router/operations.graphql b/tests/multipart/src/commonMain/graphql/router/operations.graphql
new file mode 100644
index 0000000000..c2099a2d8d
--- /dev/null
+++ b/tests/multipart/src/commonMain/graphql/router/operations.graphql
@@ -0,0 +1,9 @@
+subscription Die {
+  aNewDieWasCreated {
+    die {
+      roll
+      sides
+      color
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/multipart/src/commonMain/graphql/router/schema.sdl b/tests/multipart/src/commonMain/graphql/router/schema.sdl
new file mode 100644
index 0000000000..f293fd1658
--- /dev/null
+++ b/tests/multipart/src/commonMain/graphql/router/schema.sdl
@@ -0,0 +1,124 @@
+type AnewDieWasCreated {
+  id: ID!
+
+  die: Die
+}
+
+type Die {
+  id: ID!
+
+  sides: Int!
+
+  color: String!
+
+  roll: Int!
+}
+
+type Product implements ProductItf & SkuItf {
+  id: ID!
+
+  sku: String
+
+  name: String
+
+  package: String
+
+  variation: ProductVariation
+
+  dimensions: ProductDimension
+
+  createdBy: User
+
+  hidden: String
+
+  reviewsScore: Float!
+
+  oldField: String
+
+  reviewsCount: Int!
+
+  reviews: [Review!]!
+}
+
+type ProductDimension {
+  size: String
+
+  weight: Float
+}
+
+interface ProductItf implements SkuItf {
+  id: ID!
+
+  sku: String
+
+  name: String
+
+  package: String
+
+  variation: ProductVariation
+
+  dimensions: ProductDimension
+
+  createdBy: User
+
+  oldField: String @deprecated(reason: "refactored out")
+
+  reviewsCount: Int!
+
+  reviewsScore: Float!
+
+  reviews: [Review!]!
+}
+
+type ProductVariation {
+  id: ID!
+
+  name: String
+}
+
+type Query {
+  dice: [Die!]!
+
+  allProducts: [ProductItf]
+
+  product(id: ID!): ProductItf
+
+  review(id: Int!): Review
+}
+
+type Review {
+  id: Int!
+
+  body: String!
+
+  product: Product!
+}
+
+enum ShippingClass {
+  STANDARD
+
+  EXPRESS
+}
+
+interface SkuItf {
+  sku: String
+}
+
+type Subscription {
+  aNewDieWasCreated: AnewDieWasCreated!
+
+  aReviewWasAdded: Review
+}
+
+type User {
+  email: ID!
+
+  totalProductsCreated: Int
+
+  name: String
+}
+
+schema {
+  query: Query
+  subscription: Subscription
+}
diff --git a/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsTest.kt b/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsFakeTest.kt
similarity index 98%
rename from tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsTest.kt
rename to tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsFakeTest.kt
index b79bbdb448..dcdc03e28f 100644
--- a/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsTest.kt
+++ b/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsFakeTest.kt
@@ -10,7 +10,7 @@ import multipart.CounterSubscription
 import kotlin.test.Test
 import kotlin.test.assertContentEquals
 
-class MultipartSubscriptionsTest {
+class MultipartSubscriptionsFakeTest {
   private lateinit var mockServer: MockServer
   private lateinit var apolloClient: ApolloClient
 
diff --git a/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsRouterTest.kt b/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsRouterTest.kt
new file mode 100644
index 0000000000..7be457846a
--- /dev/null
+++ b/tests/multipart/src/commonTest/kotlin/test/MultipartSubscriptionsRouterTest.kt
@@ -0,0 +1,46 @@
+package test
+
+import com.apollographql.apollo3.ApolloClient
+import com.apollographql.apollo3.network.http.HttpNetworkTransport
+import com.apollographql.apollo3.testing.internal.runTest
+import router.DieSubscription
+import kotlin.test.Ignore
+import kotlin.test.Test
+
+/**
+ * A test that runs against https://github.com/apollographql/federated-subscriptions-poc
+ */
+@Ignore
+class MultipartSubscriptionsRouterTest {
+  @Test
+  fun routerTest() = runTest {
+    val apolloClient = ApolloClient.Builder()
+        .serverUrl("http://localhost:4040/")
+        .subscriptionNetworkTransport(
+            HttpNetworkTransport.Builder()
+                .serverUrl("http://localhost:4040/")
+                .build()
+        )
+        .build()
+
+    /**
+     * Should display something like this
+     *
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=3, sides=30, color=red)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=5, sides=31, color=blue)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=11, sides=32, color=red)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=12, sides=33, color=blue)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=21, sides=34, color=red)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=16, sides=35, color=blue)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=22, sides=36, color=red)))
+     * Got Data(aNewDieWasCreated=ANewDieWasCreated(die=Die(roll=11, sides=37, color=blue)))
+     */
+    apolloClient.subscription(DieSubscription()).toFlow().collect {
+      if (it.data != null) {
+        println("${it.data}")
+      } else {
+        it.exception!!.printStackTrace()
+      }
+    }
+  }
+}
diff --git a/tests/settings.gradle.kts b/tests/settings.gradle.kts
index 1b76206204..f81c2c186c 100644
--- a/tests/settings.gradle.kts
+++ b/tests/settings.gradle.kts
@@ -1,5 +1,4 @@
-// TODO: See https://youtrack.jetbrains.com/issue/KT-56536
-//rootProject.name = "apollo-tests"
+rootProject.name = "apollo-tests"
 
 // Include all tests
 rootProject.projectDir
@@ -14,7 +13,10 @@ rootProject.projectDir
       include(project)
     }
 
-includeBuild("../")
+includeBuild("../") {
+  // See https://youtrack.jetbrains.com/issue/KT-56536
+  name = "apollo-kotlin"
+}
 
 pluginManagement {
   includeBuild("../build-logic")