Skip to content

Commit

Permalink
Add Boolean fields to Data classes for supporting sparse update (#664)
Browse files Browse the repository at this point in the history
* added support for bitset for data types

* added support for bitset for all data types

* initialize bitset

* generate setField conditionally

* bug fixes

* adding unit tests

* cleanup

* Revert "cleanup"

This reverts commit f21e6af.

* cleanup

* updated flag name, CodeGenCliKt.run.xml

* added additional unit test without field isset

* Added descriptive help for CLI flag

* refactor builder function

* add parameters to enum constructor

* fix linting

* Revert "fix linting"

This reverts commit cd71b3a.

* fix linting, unit tests

* updating linting

* add field is set to generateJava

* Revert "add field is set to generateJava"

This reverts commit b5c7af4.

* Revert "updating linting"

This reverts commit b3513ef.

* Revert "fix linting, unit tests"

This reverts commit 7a1d567.

* update generateJava, formatting

* revert xml changes

* linting fix

* updating isSet and setField to public

* update boolean fields

* cleanup

* update boolean field generation with tests

* updating unit tests

* updating unit tests

* formatting Kotlin

* Revert "formatting Kotlin"

This reverts commit 5d76a5e.

* formatting Kotlin

* updating boolean field and setter names

* update EntitiesClientApiGenTest and ClientApiGenQueryTest

* fix more tests

* bug fix

* format kotlin

* fix unit tests

* update boolean fields

* cleanup

* fix: adding is nullable for input types

* fix: adding javapoet formatting

* fix: Adding fields for non-nullable without defaults

* cleanup

* addressing comments

* cleanup

---------

Co-authored-by: kkatelia <krutika_katelia@intuit.com>
  • Loading branch information
krutikavk and kkatelia authored May 8, 2024
1 parent 30ac67d commit 89ed33a
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CodeGenCli : CliktCommand("Generate Java sources for SCHEMA file(s)") {
)
private val language by option("--language", "-l", help = "Output language").choice("java", "kotlin", ignoreCase = true)
.default("java")
private val generateClient by option("--generate-client", "-c", help = "Genereate client api").flag(default = false)
private val generateClient by option("--generate-client", "-c", help = "Generate client api").flag(default = false)
private val generateDataTypes by option(
"--generate-data-types",
help = "Generate data types. Not needed when only generating an API"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
package com.netflix.graphql.dgs.codegen.generators.java

import com.netflix.graphql.dgs.codegen.*
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.capitalized
import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava
import com.squareup.javapoet.*
import graphql.language.*
import graphql.language.TypeName
import graphql.schema.idl.TypeUtil
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.Serializable
Expand Down Expand Up @@ -81,13 +83,15 @@ class DataTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTyp
if (config.generateDataTypes) {
val fieldDefinitions = definition.fieldDefinitions
.filterSkipped()
.map {
.map { fieldDefinition ->
val isNullable = !TypeUtil.isNonNull(fieldDefinition.type)
Field(
it.name,
typeUtils.findReturnType(it.type, useInterfaceType, true),
fieldDefinition.name,
typeUtils.findReturnType(fieldDefinition.type, useInterfaceType, true),
overrideGetter = overrideGetter,
description = it.description,
directives = it.directives
description = fieldDefinition.description,
directives = fieldDefinition.directives,
isNullable = isNullable
)
}
.plus(
Expand Down Expand Up @@ -122,6 +126,7 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy

val name = definition.name
val fieldDefinitions = definition.inputValueDefinitions.map {
val isNullable = !TypeUtil.isNonNull(it.type)
val defaultValue = it.defaultValue?.let { defVal ->
when (defVal) {
is BooleanValue -> CodeBlock.of("\$L", defVal.isValue)
Expand Down Expand Up @@ -155,7 +160,8 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy
type = typeUtils.findReturnType(it.type),
initialValue = defaultValue,
description = it.description,
directives = it.directives
directives = it.directives,
isNullable = isNullable
)
}.plus(extensions.flatMap { it.inputValueDefinitions }.map { Field(it.name, typeUtils.findReturnType(it.type)) })
return generate(name, emptyList(), fieldDefinitions, definition.description, definition.directives)
Expand All @@ -167,7 +173,7 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy
}
}

internal data class Field(val name: String, val type: com.squareup.javapoet.TypeName, val initialValue: CodeBlock? = null, val overrideGetter: Boolean = false, val interfaceType: com.squareup.javapoet.TypeName? = null, val description: Description? = null, val directives: List<Directive> = listOf())
internal data class Field(val name: String, val type: com.squareup.javapoet.TypeName, val initialValue: CodeBlock? = null, val overrideGetter: Boolean = false, val interfaceType: com.squareup.javapoet.TypeName? = null, val description: Description? = null, val directives: List<Directive> = listOf(), val isNullable: Boolean = true)

abstract class BaseDataTypeGenerator(
internal val packageName: String,
Expand Down Expand Up @@ -227,7 +233,7 @@ abstract class BaseDataTypeGenerator(

addEquals(javaType)
addHashcode(javaType)
addBuilder(javaType)
addBuilder(fields, javaType)

val javaFile = JavaFile.builder(packageName, javaType.build()).build()

Expand Down Expand Up @@ -341,7 +347,22 @@ abstract class BaseDataTypeGenerator(
constructorBuilder
.addParameter(parameterBuilder.build())
.addModifiers(Modifier.PUBLIC)
.addStatement("this.\$N = \$N", ReservedKeywordSanitizer.sanitize(it.name), ReservedKeywordSanitizer.sanitize(it.name))
}

fieldDefinitions.forEach {
val constructor = constructorBuilder
.addStatement(
"this.\$N = \$N",
ReservedKeywordSanitizer.sanitize(it.name),
ReservedKeywordSanitizer.sanitize(it.name)
)
if (it.isNullable && it.initialValue == null) {
constructorBuilder
.addStatement(
"this.\$N = true",
generateBooleanFieldName(ReservedKeywordSanitizer.sanitize(it.name))
)
}
}

javaType.addMethod(constructorBuilder.build())
Expand All @@ -360,6 +381,35 @@ abstract class BaseDataTypeGenerator(

private fun addField(fieldDefinition: Field, javaType: TypeSpec.Builder) {
addFieldWithGetterAndSetter(fieldDefinition.type, fieldDefinition, javaType)
// Generate for all nullable fields without any defaults
if (fieldDefinition.isNullable && fieldDefinition.initialValue == null) {
addIsDefinedFieldWithGetters(fieldDefinition, javaType)
}
}

private fun addIsDefinedFieldWithGetters(fieldDefinition: Field, javaType: TypeSpec.Builder) {
val fieldName = generateBooleanFieldName(ReservedKeywordSanitizer.sanitize(fieldDefinition.name))
val field = FieldSpec
.builder(com.squareup.javapoet.TypeName.BOOLEAN, fieldName)
.addModifiers(Modifier.PRIVATE)
.initializer("false")
.build()
val getterName = "${fieldName}Defined"

val getter = MethodSpec
.methodBuilder(getterName)
.addModifiers(Modifier.PUBLIC)
.returns(com.squareup.javapoet.TypeName.BOOLEAN)
.addStatement(
"return \$N",
fieldName
).build()
javaType.addField(field)
javaType.addMethod(getter)
}

private fun generateBooleanFieldName(name: String): String {
return "is${name.capitalized()}"
}

private fun addFieldWithGetterAndSetter(returnType: com.squareup.javapoet.TypeName?, fieldDefinition: Field, javaType: TypeSpec.Builder) {
Expand Down Expand Up @@ -390,13 +440,21 @@ abstract class BaseDataTypeGenerator(

val setterName = typeUtils.transformIfDefaultClassMethodExists("set${fieldDefinition.name[0].uppercase()}${fieldDefinition.name.substring(1)}", TypeUtils.Companion.setClass)
val parameterBuilder = ParameterSpec.builder(returnType, ReservedKeywordSanitizer.sanitize(fieldDefinition.name))

val setterMethodBuilder = MethodSpec.methodBuilder(setterName)
.addModifiers(Modifier.PUBLIC)
.addStatement(
"this.\$N = \$N",
ReservedKeywordSanitizer.sanitize(fieldDefinition.name),
ReservedKeywordSanitizer.sanitize(fieldDefinition.name)
)
if (fieldDefinition.isNullable && fieldDefinition.initialValue == null) {
setterMethodBuilder
.addStatement(
"this.\$N = true",
generateBooleanFieldName(ReservedKeywordSanitizer.sanitize(fieldDefinition.name))
)
}

if (fieldDefinition.directives.isNotEmpty()) {
val (annotations, comments) = applyDirectivesJava(fieldDefinition.directives, config)
Expand Down Expand Up @@ -431,13 +489,13 @@ abstract class BaseDataTypeGenerator(
)
}

private fun addBuilder(javaType: TypeSpec.Builder) {
private fun addBuilder(fields: List<Field>, javaType: TypeSpec.Builder) {
val className = ClassName.get(packageName, javaType.build().name)
val buildMethod = MethodSpec.methodBuilder("build").returns(className).addStatement(
"""
$className result = new $className();
${javaType.build().fieldSpecs.joinToString("\n") { "result.${it.name} = this.${it.name};" }}
return result
$className result = new $className();
${javaType.build().fieldSpecs.joinToString("\n") { "result.${it.name} = this.${it.name};".trimIndent() }}
return result
""".trimIndent()
).addModifiers(Modifier.PUBLIC).build()

Expand All @@ -460,10 +518,23 @@ abstract class BaseDataTypeGenerator(
.addMethod(buildMethod)

javaType.build().fieldSpecs.map {
MethodSpec.methodBuilder(it.name)
val method = MethodSpec.methodBuilder(it.name)
.addJavadoc(it.javadoc)
.returns(builderClassName)
.addStatement("this.${it.name} = ${it.name}")

val fieldName = it.name
val field = fields.find { it.name.contains(fieldName) }

if (field?.isNullable == true && field.initialValue == null) {
method
.addStatement(
"this.\$N = true",
generateBooleanFieldName(it.name)
)
}

method
.addStatement("return this")
.addParameter(ParameterSpec.builder(it.type, it.name).build())
.addModifiers(Modifier.PUBLIC).build()
Expand Down
Loading

0 comments on commit 89ed33a

Please sign in to comment.