Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to provide meaningful defaults for scalar type mapping to a specific java type in inputs #712

Closed
mrvaruntandon opened this issue Jul 10, 2024 · 4 comments · Fixed by #720

Comments

@mrvaruntandon
Copy link

Given the below setup, I am not able to generate classes where a default value could be provided to scalar:

Gradle config:

generateJava {
    schemaPaths = ["${projectDir}/src/main/resources/graphql-client"]
    packageName = 'com.example.defaultvaluetest.codegen'
    generateClient = true
    typeMapping = ["Decimal": "java.math.BigDecimal"]
}

GraphQL schema

scalar Decimal

type Query {
    api(i: myinput): String
}

input myinput{
    order: Decimal! = 1
}

Error:

error: incompatible types: int cannot be converted to BigDecimal
  private BigDecimal order = 1;

Expected output:

      private BigDecimal order = new BigDecimal(1);

the above line should get generated.

@Emily
Copy link
Contributor

Emily commented Jul 11, 2024

Hi @mrvaruntandon,

Definitely is a problem, not entirely sure how we'd fix it. I suspect we'd have to provide some sort of templating, as I don't think we'd be able to reliably reflect on the mapped type's constructor. If you have any ideas, or would be interested in submitting a PR, please do let us know. Otherwise, I'm not sure what the timeframe on a fix for this would look like.

In the meantime, you could handle the defaulting of the value within your java code, and not set the default inside the schema. This would be nearly functionally the same, in that:

  • client wouldn't have to provide a value
  • if the value was missing (or null) you could use the default value

I believe the only difference is that the client could provide a null value in their input, and it wouldn't be caught by the request validation, only later by wherever you choose to handle providing the default value in code.

@dwilkolek
Copy link
Contributor

I experimented with calling constructors. I got it to work for BigDecimal by finding correct constructor depending on default value. It wouldn't work for classes that require more parameters or cannot be extended with matching constructor.

Like you mentioned I think codegen could take new parameter with map type -> code block template. This way user could specify how to create default value. If this is good idea I can finish it up PR and add support to the rest of generators.

Draft implementation for java: #713

@dwilkolek
Copy link
Contributor

dwilkolek commented Jul 15, 2024

Hey @Emily,
I experimented a bit more with code block templates. I've got to the point that I was not sure what I'd expect as output.
I decided to implement it the same way as Locale is handled. I think it's good enough 🥲 #720

Quirky example

  scalar Decimal

  type Query {
      api(i: ApiParams): String
  }

  input ApiParams{
      value: SomeType = { someValue: "abc" }
  }

  input SomeType {
      someValue: String = "def"
  }
CodeGen(
  CodeGenConfig(
    typeMapping = mapOf(
       "SomeType" to "com.exmaple.OurSomeType",
       "ApiParams" to "com.exmaple.OurApiParams"
    ),
    codeBlockTemplates = mapOf(
      "com.exmaple.OurSomeType" to "com.exmaple.Factory.create(\$L, \"extra\")"),
      "com.exmaple.ApiParams" to "com.exmaple.Factory.apiParams(\$L)
  )
)

@mrvaruntandon
Copy link
Author

Thanks for fixing this issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants