Skip to content

Latest commit

 

History

History
208 lines (163 loc) · 6.84 KB

entities.md

File metadata and controls

208 lines (163 loc) · 6.84 KB

graphql-provider/Create project & Define entities

1. Create project

Visit https://start.spring.io/, create a Spring boot project, select Gradle project and Kotlin

image

2. UML diagram of entity objects

image

  1. There are three entities: BookStore, Book and Author
  2. There is a many-to-one association from Book to BookStore: Book.store
  3. There is a one-to-many association from BookStore to Book: BookStore.books
  4. There is a many-to-many association from Book to Author: Book.authors
  5. There is a many-to-many association from Author to Book: Author.books

3. Add dependencies

Modify the "build.gradle.kts",

  1. Add google ksp into plugins {}

    plugins {
        
        ... other plugins ...
        
        id("com.google.devtools.ksp") version "1.6.10-1.0.2"
    }
    
  2. Add the following three dependencies under dependencies {}

    dependencies {
        implementation("org.babyfish.graphql.provider:graphql-provider-starter-dgs:0.0.13")
        ksp("org.babyfish.kimmer:kimmer-ksp:0.3.1")
        runtimeOnly("io.r2dbc:r2dbc-h2:0.8.5.RELEASE")
    }
    
    1. The first dependency is graphql-provider
    2. The second dependency is a gradle tool required by kimmer, it is used to generate some source code files
    3. The third dependency is R2DBC driver of H2 database

Click the refresh button of gradle panel to let intellij down the plugin and dependencies.

4. Define entity types by kotlin

Create a new package com.example.demo.model, add 4 files under it: BookStore.kt, Book.kt, Author.kt, Gender.kt

  1. BookStore.kt
    package com.example.demo.model
    
    import org.babyfish.kimmer.sql.Entity
    import java.util.*
    
    interface BookStore: Entity<UUID> {
        val name: String
        val website: String?
        val books: List<Book>
    }
  2. Book.kt
    package com.example.demo.model
    
    import org.babyfish.kimmer.sql.Entity
    import java.math.BigDecimal
    import java.util.*
    
    interface Book: Entity<UUID> {
        val name: String
        val store: BookStore?
        val price: BigDecimal
        val authors: List<Author>
    }
  3. Author.kt
    package com.example.demo.model
    
    import org.babyfish.kimmer.sql.Entity
    import java.util.*
    
    interface Author: Entity<UUID> {
        val firstName: String
        val lastName: String
        val gender: Gender
        val books: List<Book>
    }
  4. Gender.kt
    package com.example.demo.model
    
    enum class Gender {
        MALE,
        FEMALE
    }

5. Generate source code required by strongly typed SQL DSL.

In order to use the strongly typed SQL DSL to maximize the development experience, some source code needs to be generated based on the entity interfaces. Please modify "build.gradle.kts".

  1. Configure arguments of google ksp

    ksp {
        arg("kimmer.draft", "false") // α
        arg("kimmer.table", "true") // β
        arg("kimmer.table.collection-join-only-for-sub-query", "true") // γ
    }
    
    • α: Do not generate the source code required by kimmer, which is not required for this example
    • β: Generate the source code required by kimmer-sql, which is required for this example
    • γ: Prohibit the use of collection joins in top-level queries. This switch allows developers to develop better programming habits, click here for more information
  2. Add the generated code to the gradle build path (important but easy to forget)

    kotlin {
        sourceSets.main {
            kotlin.srcDir("build/generated/ksp/main/kotlin")
        }
    }

Click the refresh button of gradle panel to let ksp generate source codes.

6. Global configuration

  1. Automatically initialize the H2 database when the app starts

    Create a file data.sql under src/main/resouces. Due to the large amount of sql code, the sql code is not listed here and you can copy the sql code from example/src/main/resources/data.sql.

    Change class com.example.demo.DempApplciation, add a spring bean

    @Bean
    fun connectionFactoryInitializer(
        connectionFactory: ConnectionFactory
    ): ConnectionFactoryInitializer =
        ConnectionFactoryInitializer().apply {
            setConnectionFactory(connectionFactory)
            setDatabasePopulator(ResourceDatabasePopulator(ClassPathResource("data.sql")))
            afterPropertiesSet()
        }
  2. Let kimmer-sql use dialect of H2 database

    Change class com.example.demo.DempApplciation, add a spring bean

    @Bean
    fun dialect() = 
        org.babyfish.kimmer.sql.runtime.dialect.H2Dialect()
  3. Tell kimmer-sql how to map the enum com.example.demo.model.Gender

    Change class com.example.demo.DempApplciation, add a spring bean

    @Bean
    fun genderProvider() =
        enumProviderByString(Gender::class) {
    	map(Gender.MALE, "M")
    	map(Gender.FEMALE, "F")
        }

    kimmer-sql provides two ways to map enum

    1. enumProviderByString

      This means to map the enum to string

    • By default the name of the enum is used
      enumProviderByString(Gender::class) // MALE, FEMALE
    • You can override the default behavior with custom strings
      enumProviderByString(Gender::class) { // M, F
          map(Gender.MALE, "M")
          map(Gender.FEMALE, "F")
      }
    1. enumProviderByInt

      This means to map the enum to integer

    • By default the ordinal of the enum is used
      enumProviderByInt(Gender::class) // 0, 1
    • You can override the default behavior with custom integers
      enumProviderByInt(Gender::class) { // 100, 200
          map(Gender.MALE, 100)
          map(Gender.FEMALE, 200)
      }

Home | Next: Map entities>