Netflix / dgs-codegen

Apache License 2.0
181 stars 99 forks source link

Option to add custom logic during Entity codegen #248

Open up-to-you opened 2 years ago

up-to-you commented 2 years ago

I'm looking for ability to add Spring Data Jdbc annotations (@Id, @MappedCollection) for generated GraphQL entities. Such option allow to reuse existing Pojos for DAO layer and eliminate tons of redundant LOC.

I see that JsonProperty is hardcoded in graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt:116.

Can you please provide some API for users, exposing some pluggable Kotlinpoet functions or something like that...

Without this option it's a disaster to duplicate Entities / Classes, then using some sort of Mappers and other annoying stuff to reach database.

EDIT

Also, all collections are mapped to List, although handwritten Set works. Most ORM / ORM-like frameworks require Set collection over List for relationships. Usually, List servers more rare cases in database mapping. Ability to set Collection type also falls into "must have" zone.

up-to-you commented 2 years ago

Seems that issue is unnecessary now. I was able to achieve fine-grained control over generated code by creating custom Gradle Task with com.netflix.graphql.dgs.codegen:graphql-dgs-codegen-core using CodeGen class.

berngp commented 2 years ago

Thanks @up-to-you, could you share your approach? We don't anticipate folks using graphql-dgs-codegen-core directly but your use-case is interesting. Maybe we could explore a mechanism to support extensions directly in the Gradle plugin.

up-to-you commented 2 years ago

Suppose we have gql dsl like this:

type Mutation {
    addSome(input: SomeInput): UUID
}

input SomeInput {
    some_field: String
    """ @org.springframework.data.annotation.Id """
    id: UUID
    """ @org.springframework.data.relational.core.mapping.MappedCollection(idColumn = "fk_id") """
    depsAInput: [DepsAInput!]!
    """ @org.springframework.data.relational.core.mapping.MappedCollection(idColumn = "fk_id") """
    depsBInput: [DepsBInput!]!
}

input DepsAInput {
    fk_id: UUID
    """ @org.springframework.data.annotation.Id """
    id: UUID
}

input DepsBInput {
    fk_id: UUID
    """ @org.springframework.data.annotation.Id """
    id: UUID
}

From this point i just created similar gradle task, which run CodeGen with CodeGenConfig.writeToFiles = false. Accessing kotlinDataTypes i was able to make dirty work on FileSpec filtering/parsing properties with annotated docs and rebuilding them via Kotlinpoet api, adding annotations from doc and replacing List with Set types (this is the most ugly part from the whole gibberish).

This attempts allow to use single source of truth as Graphql file and write CRUD as simple as:

// spring-data-jdbc
@Repository
interface SomeRepository : CrudRepository<SomeInput, UUID>
...
@DgsComponent
class SomeMutations(val someRepository: SomeRepository) {

    @DgsData(parentType = "Mutation")
    fun addSome(someInput: SomeInput) = someRepository.save(someInput).id
}