From 9263ef477df695d39e615d0a3106c466ba3ebb2c Mon Sep 17 00:00:00 2001 From: Bernardo Gomez Palacio Date: Tue, 5 Jul 2022 17:06:37 -0700 Subject: [PATCH] Adding Kotlin Entities Client API Code GenTest Adding KotlinEntitiesClientApiGenTest.kt based on EntitiesClientApiGenTest.kt. Some tests were disabled due that they expressed differences. Will follow with a different PR. --- .../dgs/codegen/EntitiesClientApiGenTest.kt | 148 ++---- .../codegen/KotlinEntitiesClientApiGenTest.kt | 495 ++++++++++++++++++ 2 files changed, 545 insertions(+), 98 deletions(-) create mode 100644 graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinEntitiesClientApiGenTest.kt diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/EntitiesClientApiGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/EntitiesClientApiGenTest.kt index 244f194ad..c36c26baa 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/EntitiesClientApiGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/EntitiesClientApiGenTest.kt @@ -47,13 +47,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -69,7 +63,7 @@ class EntitiesClientApiGenTest { assertThat(representation.typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -91,13 +85,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -111,7 +99,7 @@ class EntitiesClientApiGenTest { assertThat(representation.typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -137,13 +125,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -153,7 +135,7 @@ class EntitiesClientApiGenTest { assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieKey_Actor_ActorProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(2) + assertThat(representations).hasSize(2) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "actor") @@ -161,7 +143,7 @@ class EntitiesClientApiGenTest { assertThat(representations[1].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "name") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -182,13 +164,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -197,7 +173,7 @@ class EntitiesClientApiGenTest { assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorsProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(2) + assertThat(representations).hasSize(2) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId", "actors") @@ -205,7 +181,7 @@ class EntitiesClientApiGenTest { .toString() .contains("java.util.List") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -233,13 +209,7 @@ class EntitiesClientApiGenTest { """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -253,7 +223,7 @@ class EntitiesClientApiGenTest { assertThat(projections[6].typeSpec.name).isEqualTo("EntitiesMovieCastKey_ActorProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(3) + assertThat(representations).hasSize(3) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId", "actor") @@ -264,7 +234,7 @@ class EntitiesClientApiGenTest { assertThat(representations[2].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movie", "actor") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -287,13 +257,7 @@ class EntitiesClientApiGenTest { """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -304,7 +268,7 @@ class EntitiesClientApiGenTest { assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieActorKeyProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(2) + assertThat(representations).hasSize(2) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId") @@ -312,7 +276,7 @@ class EntitiesClientApiGenTest { assertThat(representations[1].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "name") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -334,13 +298,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -349,7 +307,7 @@ class EntitiesClientApiGenTest { assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(2) + assertThat(representations).hasSize(2) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "movieId", "actor") @@ -357,7 +315,7 @@ class EntitiesClientApiGenTest { assertThat(representations[1].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "name", "age") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -381,13 +339,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -396,12 +348,13 @@ class EntitiesClientApiGenTest { assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_GenreProjection") val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(2) + assertThat(representations).hasSize(2) assertThat(representations[0].typeSpec.name).isEqualTo("MovieRepresentation") assertThat(representations[0].typeSpec.fieldSpecs).extracting("name") .containsExactlyInAnyOrder("__typename", "id", "genre") + assertThat(representations[1].typeSpec.name).isEqualTo("MovieGenreRepresentation") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test @@ -436,13 +389,7 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") @@ -482,11 +429,11 @@ class EntitiesClientApiGenTest { assertThat(representations.first { it.typeSpec.name == "LocationRepresentation" }.typeSpec.fieldSpecs) .extracting("name").containsExactlyInAnyOrder("__typename", "id") - assertCompilesJava(codeGenResult.javaSources()) + codeGenResult.assertCompile() } @Test - fun testScalarsInEntities() { + fun `Entities can have scalar fields`() { val schema = """ type Query { movieCountry: MovieCountry @@ -500,19 +447,14 @@ class EntitiesClientApiGenTest { """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true, - typeMapping = mapOf("Long" to "java.lang.Long") - ) - ).generate() + val codeGenResult = codeGen(schema) + val representations = codeGenResult.javaDataTypes.filter { "Representation" in it.typeSpec.name } - assertThat(representations.size).isEqualTo(1) + assertThat(representations).hasSize(1) val projections = codeGenResult.clientProjections - assertThat(projections.size).isEqualTo(3) - assertCompilesJava(codeGenResult.javaSources()) + assertThat(projections).hasSize(3) + + codeGenResult.assertCompile() } @Test @@ -545,6 +487,8 @@ class EntitiesClientApiGenTest { val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } assertThat(projections).isEmpty() + + codeGenResult.assertCompile() } @Test @@ -564,15 +508,9 @@ class EntitiesClientApiGenTest { } """.trimIndent() - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - generateClientApi = true - ) - ).generate() + val codeGenResult = codeGen(schema) // then - val testClassLoader = assertCompilesJava(codeGenResult).toClassLoader() + val testClassLoader = codeGenResult.assertCompile().toClassLoader() // assert projection classes val (entityRootProjectionClass, entitiesFooKeyProjectionClass, entitiesFooKey_BarFieldProjectionClass, entitiesFooKey_MBarFieldProjection) = arrayOf( @@ -618,4 +556,18 @@ class EntitiesClientApiGenTest { .describedAs("method: $name").isNotNull.returns(returnClass) { it.returnType } } } + + companion object { + fun codeGen(schema: String): CodeGenResult { + return CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + generateClientApi = true, + language = Language.JAVA + ) + ).generate() + } + fun CodeGenResult.assertCompile() = assertCompilesJava(this) + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinEntitiesClientApiGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinEntitiesClientApiGenTest.kt new file mode 100644 index 000000000..eea23a111 --- /dev/null +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinEntitiesClientApiGenTest.kt @@ -0,0 +1,495 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.netflix.graphql.dgs.codegen + +import org.assertj.core.api.Assertions.* +import org.assertj.core.data.Index +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test + +class KotlinEntitiesClientApiGenTest { + + @Test + fun `We can have federated entities`() { + val schema = """ + type Movie @key(fields: "movieId") { + movieId: ID! @external + title: String + genre: MovieGenre + actor: Actor + } + + enum MovieGenre { + HORROR + ACTION + ROMANCE + COMEDY + } + + type Actor { + name: String + friends: Actor + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections) + .hasSize(5) + .satisfies( + { file -> + assertThat(file.typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(file.typeSpec.methodSpecs).extracting("name").containsExactly("onMovie") + }, + Index.atIndex(0) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") }, + Index.atIndex(1) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKey_GenreProjection") }, + Index.atIndex(2) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") }, + Index.atIndex(3) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKey_Actor_FriendsProjection") }, + Index.atIndex(4) + ) + + val representation = codeGenResult.kotlinDataTypes.single { "Representation" in it.name } + + assertThat(representation.name).isEqualTo("MovieRepresentation") + codeGenResult.assertCompile() + } + + @Test + fun `We can have federated entities and queries`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId") { + movieId: ID! @external + title: String + actor: Actor + } + + type Actor { + name: String + friends: Actor + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name").containsExactly("onMovie") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") + assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieKey_Actor_FriendsProjection") + + val representation = codeGenResult.kotlinDataTypes.single { "Representation" in it.name } + assertThat(representation.name).isEqualTo("MovieRepresentation") + codeGenResult.assertCompile() + } + + @Test + fun `An entity can have a field that is an interface`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "actor { name }") { + movieId: ID! + title: String + actor: IActor @external + } + + interface IActor { + name: String + } + + type Actor implements IActor { + name: String + friends: Actor + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name").containsExactly("onMovie") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") + assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieKey_Actor_ActorProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + + assertThat(representations).hasSize(2) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + assertThat(representations[1].name).isEqualTo("IActorRepresentation") + + codeGenResult.assertCompile() + } + + @Test + fun `We can have entities with arrays and nested keys`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId actors { name }") { + movieId: ID! @external + title: String + actors: [Actor!]! + } + + type Actor @key(fields: "name") { + name: String + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name").containsExactly("onMovie", "onActor") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorsProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(2) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + + codeGenResult.assertCompile() + } + + @Test + fun `We can have entities with nested keys`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId actor { name }") { + movieId: ID! @external + title: String + actor: Person + } + + type Person { + name: String @external + age: Int + } + + type MovieCast @key(fields: "movie { movieId actor { name } } actor{name}") { + movie: Movie + actor: Person + } + + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name") + .containsExactlyInAnyOrder("onMovie", "onMovieCast") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") + assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieCastKeyProjection") + assertThat(projections[4].typeSpec.name).isEqualTo("EntitiesMovieCastKey_MovieProjection") + assertThat(projections[5].typeSpec.name).isEqualTo("EntitiesMovieCastKey_Movie_ActorProjection") + assertThat(projections[6].typeSpec.name).isEqualTo("EntitiesMovieCastKey_ActorProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(3) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + assertThat(representations[1].name).isEqualTo("PersonRepresentation") + assertThat(representations[2].name).isEqualTo("MovieCastRepresentation") + + codeGenResult.assertCompile() + } + + @Test + fun `We can have multiple entities with keys`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId") { + movieId: ID! @external + title: String + actor: MovieActor + } + + type MovieActor @key(fields: "name") { + name: String @external + age: Int + } + + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name") + .containsExactlyInAnyOrder("onMovie", "onMovieActor") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") + assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieActorKeyProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(2) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + assertThat(representations[1].name).isEqualTo("MovieActorRepresentation") + + codeGenResult.assertCompile() + } + + @Test + fun `Entities can have nested complex keys`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId actor { name age }") { + movieId: ID! @external + title: String + actor: Person + } + + type Person { + name: String @external + age: Int + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections) + .hasSize(3) + .satisfies( + { file -> + assertThat(file.typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(file.typeSpec.methodSpecs).extracting("name").containsExactly("onMovie") + }, + Index.atIndex(0) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") }, + Index.atIndex(1) + ) + .satisfies( + { file -> assertThat(file.typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") }, + Index.atIndex(2) + ) + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(2) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + assertThat(representations[1].name).isEqualTo("PersonRepresentation") + + codeGenResult.assertCompile() + } + + // TODO MovieGenreRepresentation is missing. + @Test + @Disabled + fun `Entities can have keys that are enums`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "id genre") { + id: ID! @external + genre: MovieGenre + title: String + } + + enum MovieGenre { + HORROR + ACTION + ROMANCE + COMEDY + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name").containsExactlyInAnyOrder("onMovie") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_GenreProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(2) + assertThat(representations[0].name).isEqualTo("MovieRepresentation") + assertThat(representations[1].name).isEqualTo("MovieGenreRepresentation") + + codeGenResult.assertCompile() + } + + // TODO understand why we are missing Person and MovieGenre Representations + @Test + @Disabled + fun `Entities can have the @key directive used multiple times`() { + val schema = """ + type Movie @key(fields: "id genre") @key(fields: "id actor{ id }") @key(fields: "id location { id }") { + id: ID! @external + title: String + genre: MovieGenre + actor: Person + location: Location + } + + enum MovieGenre { + HORROR + ACTION + ROMANCE + COMEDY + } + + type Person @extends { + id: ID @external + name: String + role: Role + } + + enum Role { ATL BTL } + + type Location { + id: ID + name: String + } + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections[0].typeSpec.name).isEqualTo("EntitiesProjectionRoot") + assertThat(projections[0].typeSpec.methodSpecs).extracting("name").containsExactlyInAnyOrder("onMovie") + assertThat(projections[1].typeSpec.name).isEqualTo("EntitiesMovieKeyProjection") + assertThat(projections[2].typeSpec.name).isEqualTo("EntitiesMovieKey_GenreProjection") + assertThat(projections[3].typeSpec.name).isEqualTo("EntitiesMovieKey_ActorProjection") + assertThat(projections[4].typeSpec.name).isEqualTo("EntitiesMovieKey_Actor_RoleProjection") + assertThat(projections[5].typeSpec.name).isEqualTo("EntitiesMovieKey_LocationProjection") + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations.map { it.name }) + .containsExactlyInAnyOrder( + "MovieRepresentation", + "MovieGenreRepresentation", + "PersonRepresentation", + "LocationRepresentation" + ) + codeGenResult.assertCompile() + } + + @Test + fun `Entities can have scalar fields`() { + val schema = """ + type Query { + movieCountry: MovieCountry + } + + type MovieCountry @key(fields : "movieId country") { + country: String + movieId: Long + } + scalar Long + + """.trimIndent() + + val codeGenResult = codeGen(schema) + + val representations = codeGenResult.kotlinDataTypes.filter { "Representation" in it.name } + assertThat(representations).hasSize(1) + val projections = codeGenResult.clientProjections + assertThat(projections).hasSize(3) + + codeGenResult.assertCompile() + } + + @Test + fun `CodeGen can be configured to skip entities`() { + val schema = """ + type Query { + search: Movie + } + + type Movie @key(fields: "movieId") { + movieId: ID! @external + title: String + actor: Actor + } + + type Actor { + name: String + friends: Actor + } + """.trimIndent() + + val codeGenResult = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + generateClientApi = true, + skipEntityQueries = true, + language = Language.KOTLIN + ) + ).generate() + + val projections = codeGenResult.clientProjections.filter { "Entities" in it.typeSpec.name } + assertThat(projections).isEmpty() + + codeGenResult.assertCompile() + } + + companion object { + fun codeGen(schema: String): CodeGenResult { + return CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + generateClientApi = true, + language = Language.KOTLIN + ) + ).generate() + } + + fun CodeGenResult.assertCompile() = assertCompilesKotlin(this) + } +}