Skip to content

Commit

Permalink
Codegen casts hardcoded values in queries to Strings regardless of type
Browse files Browse the repository at this point in the history
Closes #841
  • Loading branch information
sav007 committed Apr 13, 2018
1 parent 94a00e3 commit 9ac1639
Show file tree
Hide file tree
Showing 41 changed files with 600 additions and 115 deletions.
2 changes: 1 addition & 1 deletion apollo-compiler/gradle/update-test-IR-files.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class UpdateTestIRFilesTask extends DefaultTask {
apolloCodeGenProcess.waitFor()
def error = apolloCodeGenProcess.err.text
if (error != null && !error.isEmpty()) {
logger.error("Failed to generate IR file for: ${testDir.name} reason:" +runtimeError)
logger.error("Failed to generate IR file for: ${testDir.name} reason:" +error)
}
//apollo code-gen has not std output if successful.
def runtimeError = apolloCodeGenProcess.in.text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,18 +220,6 @@ class BuilderTypeSpecBuilder(
.build()
}

private fun Number.castTo(type: TypeName): Number {
return if (type == TypeName.INT || type == TypeName.INT.box()) {
toInt()
} else if (type == TypeName.LONG || type == TypeName.LONG.box()) {
toLong()
} else if (type == TypeName.FLOAT || type == TypeName.FLOAT.box()) {
toDouble()
} else {
this
}
}

private fun TypeName.isEnum(typeDeclarations: List<TypeDeclaration>): Boolean {
return ((this is ClassName) && typeDeclarations.count { it.kind == "EnumType" && it.name == simpleName() } > 0)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class GraphQLCompiler {
const val FILE_EXTENSION = "graphql"
@JvmField
val OUTPUT_DIRECTORY = listOf("generated", "source", "apollo")
const val APOLLOCODEGEN_VERSION = "0.18.3"
const val APOLLOCODEGEN_VERSION = "0.19.1"
}

data class Arguments(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,18 @@ fun MethodSpec.withWildCardReturnType(forTypeNames: List<String>): MethodSpec {
}
}

fun Number.castTo(type: TypeName): Number {
return if (type == TypeName.INT || type == TypeName.INT.box()) {
toInt()
} else if (type == TypeName.LONG || type == TypeName.LONG.box()) {
toLong()
} else if (type == TypeName.FLOAT || type == TypeName.FLOAT.box()) {
toDouble()
} else {
this
}
}

object Util {
const val RESPONSE_FIELD_MAPPER_TYPE_NAME: String = "Mapper"
const val MEMOIZED_HASH_CODE_VAR: String = "\$hashCode"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.apollographql.apollo.compiler.ir

data class Argument(
val name: String,
val value: Any,
val type: String
)
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.apollographql.apollo.compiler.ir

import com.apollographql.apollo.compiler.*

import com.squareup.javapoet.*
import java.util.*
import javax.lang.model.element.Modifier

data class Field(
val responseName: String,
val fieldName: String,
val type: String,
val args: List<Map<String, Any>>? = null,
val args: List<Argument>? = null,
val isConditional: Boolean = false,
val fields: List<Field>? = null,
val fragmentSpreads: List<String>? = null,
Expand Down Expand Up @@ -73,13 +71,28 @@ data class Field(
}

fun argumentCodeBlock(): CodeBlock {
if (args == null || args.isEmpty()) {
return CodeBlock.builder().add("null").build()
}
return jsonMapToCodeBlock(args.fold(HashMap<String, Any>(), { map, arg ->
map.put(arg["name"].toString(), arg["value"]!!)
return@fold map
}))
if (args == null || args.isEmpty()) return CodeBlock.of("null")

val mapBuilderClass = ClassNames.parameterizedUnmodifiableMapBuilderOf(String::class.java, Any::class.java)
return args
.map { (name, value, type) ->
when (value) {
is Number -> {
val scalarType = ScalarType.forName(type.removeSuffix("!"))
when (scalarType) {
is ScalarType.INT -> CodeBlock.of(".put(\$S, \$L)\n", name, value.toInt())
is ScalarType.FLOAT -> CodeBlock.of(".put(\$S, \$Lf)\n", name, value.toDouble())
else -> CodeBlock.of(".put(\$S, \$L)\n", name, value)
}
}
is Boolean -> CodeBlock.of(".put(\$S, \$L)\n", name, value)
is Map<*, *> -> CodeBlock.of(".put(\$S, \$L)\n", name, jsonMapToCodeBlock(value as Map<String, Any?>))
else -> CodeBlock.of(".put(\$S, \$S)\n", name, value)
}
}
.fold(CodeBlock.builder().add("new \$T(\$L)\n", mapBuilderClass, args.size), CodeBlock.Builder::add)
.add(".build()")
.build()
}

fun formatClassName() = responseName.capitalize().let { if (isList()) it.singularize() else it }
Expand All @@ -93,22 +106,20 @@ data class Field(

private fun isList(): Boolean = type.removeSuffix("!").let { it.startsWith('[') && it.endsWith(']') }

private fun jsonMapToCodeBlock(jsonMap: Map<String, Any?>): CodeBlock {
return jsonMap.entries.map { entry ->
val codeBuilder = CodeBlock.builder()
if (entry.value is Map<*, *>) {
@Suppress("UNCHECKED_CAST")
codeBuilder.add(".put(\$S, ", entry.key).add("\$L)\n", jsonMapToCodeBlock(entry.value as Map<String, Any?>))
} else {
codeBuilder.add(".put(\$S, \$S)\n", entry.key, entry.value).build()
}
codeBuilder.build()
}.fold(CodeBlock.builder().add("new \$T(\$L)\n",
ClassNames.parameterizedUnmodifiableMapBuilderOf(String::class.java, Any::class.java),
jsonMap.size
).indent(), CodeBlock.Builder::add)
private fun jsonMapToCodeBlock(map: Map<String, Any?>): CodeBlock {
val mapBuilderClass = ClassNames.parameterizedUnmodifiableMapBuilderOf(String::class.java, Any::class.java)
return map
.map { (key, value) ->
if (value is Map<*, *>) {
CodeBlock.of(".put(\$S, \$L)\n", key, jsonMapToCodeBlock(value as Map<String, Any?>))
} else {
CodeBlock.of(".put(\$S, \$S)\n", key, value)
}
}
.fold(CodeBlock.builder().add("new \$T(\$L)\n", mapBuilderClass, map.size).indent(), CodeBlock.Builder::add)
.add(".build()")
.unindent()
.add(".build()").build()
.build()
}

private fun toTypeName(responseType: String, context: CodeGenerationContext): TypeName {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@ sealed class ScalarType(val name: String) {
object INT : ScalarType("Int")
object BOOLEAN : ScalarType("Boolean")
object FLOAT : ScalarType("Float")

companion object {
fun forName(name: String): ScalarType? = when (name) {
ScalarType.STRING.name -> ScalarType.STRING
ScalarType.INT.name -> ScalarType.INT
ScalarType.BOOLEAN.name -> ScalarType.BOOLEAN
ScalarType.FLOAT.name -> ScalarType.FLOAT
else -> null
}
}
}
2 changes: 1 addition & 1 deletion apollo-compiler/src/test/graphql/apollo-codegen.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
apollo-codegen version=0.18.3
apollo-codegen version=0.19.1
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"value": {
"kind": "Variable",
"variableName": "episode"
}
},
"type": "Episode"
},
{
"name": "review",
Expand All @@ -48,7 +49,8 @@
},
"blue": 0
}
}
},
"type": "ReviewInput"
}
],
"isConditional": false,
Expand Down Expand Up @@ -77,7 +79,8 @@
"args": [
{
"name": "unit",
"value": "FOOT"
"value": "FOOT",
"type": "LengthUnit"
}
],
"isConditional": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,24 +179,24 @@ public void marshal(InputFieldWriter writer) throws IOException {
public static class Data implements Operation.Data {
static final ResponseField[] $responseFields = {
ResponseField.forObject("heroWithReview", "heroWithReview", new UnmodifiableMapBuilder<String, Object>(2)
.put("review", new UnmodifiableMapBuilder<String, Object>(2)
.put("stars", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "stars")
.put("episode", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "episode")
.build())
.put("review", new UnmodifiableMapBuilder<String, Object>(2)
.put("stars", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "stars")
.build())
.put("favoriteColor", new UnmodifiableMapBuilder<String, Object>(3)
.put("red", "0.0")
.put("green", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "greenValue")
.put("favoriteColor", new UnmodifiableMapBuilder<String, Object>(3)
.put("red", "0.0")
.put("green", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "greenValue")
.build())
.put("blue", "0.0")
.put("blue", "0.0")
.build())
.build())
.put("episode", new UnmodifiableMapBuilder<String, Object>(2)
.put("kind", "Variable")
.put("variableName", "episode")
.build())
.build(), true, Collections.<ResponseField.Condition>emptyList())
};

Expand Down Expand Up @@ -280,7 +280,7 @@ public static class HeroWithReview {
ResponseField.forString("__typename", "__typename", null, false, Collections.<ResponseField.Condition>emptyList()),
ResponseField.forString("name", "name", null, false, Collections.<ResponseField.Condition>emptyList()),
ResponseField.forDouble("height", "height", new UnmodifiableMapBuilder<String, Object>(1)
.put("unit", "FOOT")
.put("unit", "FOOT")
.build(), true, Collections.<ResponseField.Condition>emptyList())
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query TestQuery {
reviews(episode: JEDI, starsInt: 10, starsFloat: 9.9) {
stars
commentary
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"operations": [
{
"filePath": "src/test/graphql/com/example/arguments_hardcoded/TestOperation.graphql",
"operationName": "TestQuery",
"operationType": "query",
"rootType": "Query",
"variables": [],
"source": "query TestQuery {\n reviews(episode: JEDI, starsInt: 10, starsFloat: 9.9) {\n __typename\n stars\n commentary\n }\n}",
"fields": [
{
"responseName": "reviews",
"fieldName": "reviews",
"type": "[Review]",
"args": [
{
"name": "episode",
"value": "JEDI",
"type": "Episode!"
},
{
"name": "starsInt",
"value": 10,
"type": "Int"
},
{
"name": "starsFloat",
"value": 9.9,
"type": "Float"
}
],
"isConditional": false,
"isDeprecated": false,
"deprecationReason": null,
"fields": [
{
"responseName": "__typename",
"fieldName": "__typename",
"type": "String!",
"isConditional": false
},
{
"responseName": "stars",
"fieldName": "stars",
"type": "Int!",
"isConditional": false,
"description": "The number of stars this review gave, 1-5",
"isDeprecated": false,
"deprecationReason": null
},
{
"responseName": "commentary",
"fieldName": "commentary",
"type": "String",
"isConditional": false,
"description": "Comment about the movie",
"isDeprecated": false,
"deprecationReason": null
}
],
"fragmentSpreads": [],
"inlineFragments": []
}
],
"fragmentSpreads": [],
"inlineFragments": [],
"fragmentsReferenced": [],
"sourceWithFragments": "query TestQuery {\n reviews(episode: JEDI, starsInt: 10, starsFloat: 9.9) {\n __typename\n stars\n commentary\n }\n}",
"operationId": "a6746506c2fb20405972e7e76920eec4aa2e5e02dc429cfbd1585a4f1787b0d9"
}
],
"fragments": [],
"typesUsed": []
}
Loading

0 comments on commit 9ac1639

Please sign in to comment.